added Maze game
This commit is contained in:
		
							
								
								
									
										46
									
								
								src/game-maze-context2d.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/game-maze-context2d.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,46 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
  <title>Game: Maze</title>
 | 
			
		||||
  <link rel="icon" type="image/x-icon" href="./favicon.ico">
 | 
			
		||||
  <link rel="stylesheet" href="css/game.css" />
 | 
			
		||||
  <link rel="stylesheet" href="css/main.css" />
 | 
			
		||||
 | 
			
		||||
  <script src="term/wterminal.js"></script>
 | 
			
		||||
  <script src="js/game-maze-context2d.js"></script>
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
  <header>
 | 
			
		||||
    <button title="Dark theme on/off" onclick="toggleTheme();">☀</button>
 | 
			
		||||
    <a href="index.html">Willem Games</a>
 | 
			
		||||
  </header>
 | 
			
		||||
 | 
			
		||||
  <main>
 | 
			
		||||
    <h1>Game: Maze</h1>
 | 
			
		||||
 | 
			
		||||
    <div class="game-area" id="game-area">Loading ...</div>
 | 
			
		||||
 | 
			
		||||
    <h2>How to:</h2>
 | 
			
		||||
    <p>Use the arrow keys up, down, left and right to move, or [W], [S], [A] and [D].<br>
 | 
			
		||||
      Press spacebar or enter, to select.</p>
 | 
			
		||||
 | 
			
		||||
    <button onclick="startMaze('game-area', 480, 320, 1);">start normal</button>
 | 
			
		||||
    <button onclick="startMaze('game-area', 320 , 480, 1);">start portrait</button>
 | 
			
		||||
    <button onclick="startMaze('game-area', 800 , 640, 1);">start large</button>
 | 
			
		||||
    <script>
 | 
			
		||||
      WTerminal.instalDropdownTerminal();
 | 
			
		||||
      startMaze('game-area', 800, 640, 1); // startGame(element-id, width, height, zoom)
 | 
			
		||||
    </script>
 | 
			
		||||
  </main>
 | 
			
		||||
 | 
			
		||||
  <footer>
 | 
			
		||||
    <p class="float-right">Author: Ward Truyen</p>
 | 
			
		||||
  </footer>
 | 
			
		||||
 | 
			
		||||
  <script src="js/theme.js"></script>
 | 
			
		||||
  <script src="term/wterminal-autoextend.js"></script>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
@@ -40,6 +40,7 @@
 | 
			
		||||
  <script src="js/theme.js"></script>
 | 
			
		||||
  <script src="js/game-pong-context2d.js"></script>
 | 
			
		||||
  <script src="js/game-tetris-context2d.js"></script>
 | 
			
		||||
  <script src="js/game-maze-context2d.js"></script>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@
 | 
			
		||||
    <ul>
 | 
			
		||||
      <li> <a href="game-pong-context2d.html">Ping pong (context2d)</a></li>
 | 
			
		||||
      <li> <a href="game-tetris-context2d.html">Tetris (context2d)</a></li>
 | 
			
		||||
      <li> <a href="game-maze-context2d.html">Maze game(context2d)</a></li>
 | 
			
		||||
      <li> <a href="test-collision.html">Collision test(context2d)</a> ⚒WIP⚒</li>
 | 
			
		||||
    </ul>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										692
									
								
								src/js/game-maze-context2d.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										692
									
								
								src/js/game-maze-context2d.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,692 @@
 | 
			
		||||
// this uses the Backtracking Algorithm to generate a maze
 | 
			
		||||
class Maze_CTX2D {
 | 
			
		||||
  static get DEBUG_PARENT_OBJECT() { return true; };
 | 
			
		||||
  static get AUTO_CONTINUE_ON_FOCUS() { return false; };
 | 
			
		||||
  static get SHOW_FPS_INTERVAL() { return 1000 / 4; }; // four times per second
 | 
			
		||||
 | 
			
		||||
  static get KEY_ARROW_UP() { return 'ArrowUp'; };
 | 
			
		||||
  static get KEY_ARROW_DOWN() { return 'ArrowDown'; };
 | 
			
		||||
  static get KEY_ARROW_LEFT() { return 'ArrowLeft'; };
 | 
			
		||||
  static get KEY_ARROW_RIGHT() { return 'ArrowRight'; };
 | 
			
		||||
  static get KEY_W() { return 'w'; };
 | 
			
		||||
  static get KEY_S() { return 's'; };
 | 
			
		||||
  static get KEY_A() { return 'a'; };
 | 
			
		||||
  static get KEY_D() { return 'd'; };
 | 
			
		||||
  static get KEY_ENTER() { return 'Enter'; };
 | 
			
		||||
  static get KEY_SPACEBAR() { return ' '; };
 | 
			
		||||
  static get KEY_ESCAPE() { return 'Escape'; };
 | 
			
		||||
 | 
			
		||||
  static get STATE_MENU() { return 0; };
 | 
			
		||||
  static get STATE_MAP_GEN_ANIM() { return 1; };
 | 
			
		||||
  static get STATE_PLAYING() { return 2; };
 | 
			
		||||
  static get STATE_ENDED() { return 3; };
 | 
			
		||||
  static get ANIMATION_DELAY() { return 10; };
 | 
			
		||||
 | 
			
		||||
  animationRequestId = 0;
 | 
			
		||||
  running = false;
 | 
			
		||||
 | 
			
		||||
  constructor(divId, width, height, difficulty = 1, showFps = false) {
 | 
			
		||||
    this.createCanvas(divId, width, height);
 | 
			
		||||
    this.canvasEl.title = "Playing: Maze";
 | 
			
		||||
    this.ctx = this.canvasEl.getContext("2d");
 | 
			
		||||
    this.ctx.textAlign = "center";
 | 
			
		||||
 | 
			
		||||
    this.audioCtx = new AudioContext();
 | 
			
		||||
    this.sounds = [];
 | 
			
		||||
    this.sounds[0] = new Audio('./snd/short-success.mp3');
 | 
			
		||||
    this.audioCtx.createMediaElementSource(this.sounds[0]).connect(this.audioCtx.destination);
 | 
			
		||||
    this.sounds[1] = new Audio('./snd/footstep.mp3');
 | 
			
		||||
    this.audioCtx.createMediaElementSource(this.sounds[1]).connect(this.audioCtx.destination);
 | 
			
		||||
    this.sounds[2] = new Audio('./snd/glass-knock.mp3');
 | 
			
		||||
    this.audioCtx.createMediaElementSource(this.sounds[2]).connect(this.audioCtx.destination);
 | 
			
		||||
    this.sounds[3] = new Audio('./snd/flash.mp3');
 | 
			
		||||
    this.audioCtx.createMediaElementSource(this.sounds[3]).connect(this.audioCtx.destination);
 | 
			
		||||
    this.sounds[4] = new Audio('./snd/metronome.mp3');
 | 
			
		||||
    this.audioCtx.createMediaElementSource(this.sounds[4]).connect(this.audioCtx.destination);
 | 
			
		||||
 | 
			
		||||
    this.showFps = showFps;
 | 
			
		||||
    if (showFps) {
 | 
			
		||||
      // add framecounter and fps variables and html
 | 
			
		||||
      this.frameCounter = 0;
 | 
			
		||||
      this.initTime = performance.now();
 | 
			
		||||
      const el = document.createElement('p');
 | 
			
		||||
      this.frameLabel = document.createElement('span');
 | 
			
		||||
      const floatRight = document.createElement('span');
 | 
			
		||||
      floatRight.style = "float: right;";
 | 
			
		||||
      this.fpsCounter = 0;
 | 
			
		||||
      this.fpsLabel = document.createElement('span');
 | 
			
		||||
      el.appendChild(document.createTextNode('fps: '));
 | 
			
		||||
      el.appendChild(this.fpsLabel);
 | 
			
		||||
      floatRight.appendChild(document.createTextNode('frame: '));
 | 
			
		||||
      floatRight.appendChild(this.frameLabel);
 | 
			
		||||
      el.appendChild(floatRight);
 | 
			
		||||
      this.divEl.appendChild(el);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.setDifficulty(difficulty);
 | 
			
		||||
    this.gameState = Maze_CTX2D.STATE_MENU;
 | 
			
		||||
    this.canvasEl.addEventListener("keydown", (e) => this.onKeyDown(e));
 | 
			
		||||
    this.canvasEl.addEventListener("keyup", (e) => this.onKeyUp(e));
 | 
			
		||||
    this.canvasEl.addEventListener("blur", (e) => this.onBlur(e));
 | 
			
		||||
    this.canvasEl.addEventListener("focus", (e) => this.onFocus(e));
 | 
			
		||||
 | 
			
		||||
    if (Maze_CTX2D.DEBUG_PARENT_OBJECT) window.game = this;
 | 
			
		||||
    if (typeof WTerminal === "function") {
 | 
			
		||||
      WTerminal.terminalAddCommand("restartgame", (t) => this.terminalRestartGame(t));
 | 
			
		||||
      WTerminal.terminalAddCommand("printgame", (t) => t.printVar(this, "maze"));
 | 
			
		||||
      WTerminal.printLn("new Maze: @", divId, ' ', width, 'x', height, ' difficulty=', difficulty, ' showFps=', showFps);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.drawCanvas();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  newGame(gridWidth, gridHeight) {
 | 
			
		||||
    gridWidth -= gridWidth % 2; gridWidth++;
 | 
			
		||||
    gridHeight -= gridHeight % 2; gridHeight++;
 | 
			
		||||
 | 
			
		||||
    this.gridWidth = gridWidth;
 | 
			
		||||
    this.gridHeight = gridHeight;
 | 
			
		||||
    this.gridCellWidth = this.width / gridWidth;
 | 
			
		||||
    this.gridCellHeight = this.height / gridHeight;
 | 
			
		||||
    this.gridCellSize = Math.floor(Math.min(this.gridCellWidth, this.gridCellHeight));
 | 
			
		||||
    this.mapWidth = gridWidth * this.gridCellSize;
 | 
			
		||||
    this.mapHeight = gridHeight * this.gridCellSize;
 | 
			
		||||
    this.mapOffsetX = (this.width - this.mapWidth) / 2;
 | 
			
		||||
    this.mapOffsetY = (this.height - this.mapHeight) / 2;
 | 
			
		||||
 | 
			
		||||
    var result = this.generateBacktrackingMaze(gridWidth, gridHeight);
 | 
			
		||||
    this.maze = result.maze;
 | 
			
		||||
    this.animation = result.animation;
 | 
			
		||||
    this.animationPos = 0;
 | 
			
		||||
    this.animationStepTime = 0;
 | 
			
		||||
    this.animationStepDelay = Maze_CTX2D.ANIMATION_DELAY / this.animation.length;
 | 
			
		||||
    this.player = { x: 1, y: 0 };
 | 
			
		||||
    // console.log("animation", this.animation);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  playSound(index) {
 | 
			
		||||
    try {
 | 
			
		||||
      const snd = this.sounds[index];
 | 
			
		||||
      snd.currentTime = 0;
 | 
			
		||||
      snd.play();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      console.log(`Failed to play sound '${index}': ${e}}`)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  createCanvas(divId, width = 0, height = 0, zoom = 1) {
 | 
			
		||||
    this.divEl = document.getElementById(divId);
 | 
			
		||||
    if (this.divEl === null) throw new Error("elementId not found: " + divId);
 | 
			
		||||
    while (this.divEl.firstChild) {
 | 
			
		||||
      this.divEl.removeChild(this.divEl.lastChild);
 | 
			
		||||
    }
 | 
			
		||||
    this.canvasEl = this.divEl.appendChild(document.createElement("canvas"));
 | 
			
		||||
    const c = this.canvasEl;
 | 
			
		||||
    this.width = width;
 | 
			
		||||
    this.height = height;
 | 
			
		||||
    if (width > 0 && height > 0) {
 | 
			
		||||
      c.style.width = width * zoom + 'px';
 | 
			
		||||
      c.style.height = height * zoom + 'px';
 | 
			
		||||
      c.width = width;
 | 
			
		||||
      c.height = height;
 | 
			
		||||
    }
 | 
			
		||||
    c.tabIndex = 0; // improtant for keyboard focus!
 | 
			
		||||
    // c.style.imageRendering = 'pixelated';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  drawCanvas() {
 | 
			
		||||
    if (this.showFps) {
 | 
			
		||||
      this.frameCounter++;
 | 
			
		||||
      this.fpsCounter++;
 | 
			
		||||
 | 
			
		||||
      const now = performance.now();
 | 
			
		||||
      const diff = now - this.initTime;
 | 
			
		||||
      if (Maze_CTX2D.SHOW_FPS_INTERVAL < diff || !this.running) {
 | 
			
		||||
        this.initTime = now;
 | 
			
		||||
        const seconds = diff / 1000;
 | 
			
		||||
        const fps = this.fpsCounter / seconds;
 | 
			
		||||
        this.fpsCounter = 0;
 | 
			
		||||
        if (this.frameLabel) this.frameLabel.innerHTML = this.frameCounter;
 | 
			
		||||
        if (this.fpsLabel) {
 | 
			
		||||
          this.fpsLabel.innerHTML = Math.round((fps + Number.EPSILON) * 100) / 100;
 | 
			
		||||
          if (!this.running) this.fpsLabel.innerHTML += " (not running)";
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    const ctx = this.ctx;
 | 
			
		||||
    ctx.clearRect(0, 0, this.width, this.height);
 | 
			
		||||
 | 
			
		||||
    if (this.gameState == Maze_CTX2D.STATE_MENU) {
 | 
			
		||||
      ctx.strokeStyle = 'black';
 | 
			
		||||
      ctx.fillStyle = "#4080ff";
 | 
			
		||||
      const FONT_SIZE = this.width > 440 ? 24 : 16;
 | 
			
		||||
      const x = this.width / 2;
 | 
			
		||||
      const y = this.height / 2;
 | 
			
		||||
      let text = "Menu";
 | 
			
		||||
      ctx.font = "bold " + (2 * FONT_SIZE) + "px serif";
 | 
			
		||||
      ctx.fillText(text, x, y - 3 * FONT_SIZE);
 | 
			
		||||
      ctx.strokeText(text, x, y - 3 * FONT_SIZE);
 | 
			
		||||
 | 
			
		||||
      ctx.font = "bold " + FONT_SIZE + "px mono";
 | 
			
		||||
      ctx.fillStyle = "#b0b0b0";
 | 
			
		||||
      text = `Difficulty: ${this.difficulty}`;
 | 
			
		||||
      ctx.fillText(text, x, y + 0 * FONT_SIZE);
 | 
			
		||||
      ctx.strokeText(text, x, y + 0 * FONT_SIZE);
 | 
			
		||||
      text = `Size: ${this.gridWidth} x ${this.gridHeight}`;
 | 
			
		||||
      ctx.fillText(text, x, y + 2 * FONT_SIZE);
 | 
			
		||||
      ctx.strokeText(text, x, y + 2 * FONT_SIZE);
 | 
			
		||||
      if (this.isFocused) return;
 | 
			
		||||
      this.drawBanner("Click here to continue. (unfocused)");
 | 
			
		||||
    } else if (this.gameState == Maze_CTX2D.STATE_MAP_GEN_ANIM) {
 | 
			
		||||
      ctx.fillStyle = "#404040";
 | 
			
		||||
      ctx.fillRect(this.mapOffsetX, this.mapOffsetY, this.mapWidth, this.mapHeight);
 | 
			
		||||
      ctx.fillStyle = "blue";
 | 
			
		||||
      for (let i = 0; i < this.animationPos; i++) {
 | 
			
		||||
        const animationStep = this.animation[i];
 | 
			
		||||
        if (animationStep.state == 0) {
 | 
			
		||||
          //clearRect
 | 
			
		||||
          ctx.clearRect(this.mapOffsetX + animationStep.x * this.gridCellSize,
 | 
			
		||||
            this.mapOffsetY + animationStep.y * this.gridCellSize, this.gridCellSize, this.gridCellSize);
 | 
			
		||||
        } else {
 | 
			
		||||
          //fillRect
 | 
			
		||||
          // ctx.fillRect(this.mapOffsetX + animationStep.x * this.gridCellSize,
 | 
			
		||||
          //   this.mapOffsetY + animationStep.y * this.gridCellSize, this.gridCellSize, this.gridCellSize);
 | 
			
		||||
          ctx.beginPath();
 | 
			
		||||
          ctx.arc(this.mapOffsetX + (0.5 + animationStep.x) * this.gridCellSize,
 | 
			
		||||
            this.mapOffsetY + (0.5 + animationStep.y) * this.gridCellSize,
 | 
			
		||||
            this.gridCellSize / 2, 0, Math.PI * 2);
 | 
			
		||||
          ctx.fill();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (!this.running) {
 | 
			
		||||
        if (this.isFocused)
 | 
			
		||||
          this.drawBanner("press space to continue. (paused)");
 | 
			
		||||
        else
 | 
			
		||||
          this.drawBanner("Click here to continue. (unfocused)");
 | 
			
		||||
      }
 | 
			
		||||
    } else {// Maze_CTX2D.STATE_ENDED & Maze_CTX2D.STATE_PLAYING
 | 
			
		||||
      ctx.fillStyle = "#505050";
 | 
			
		||||
      for (let i = 0; i < this.maze.length; i++) {
 | 
			
		||||
        for (let j = 0; j < this.maze[i].length; j++) {
 | 
			
		||||
          if (this.maze[i][j] != 0) {
 | 
			
		||||
            ctx.fillRect(this.mapOffsetX + j * this.gridCellSize,
 | 
			
		||||
              this.mapOffsetY + i * this.gridCellSize, this.gridCellSize, this.gridCellSize);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      ctx.fillStyle = "red";
 | 
			
		||||
      ctx.beginPath();
 | 
			
		||||
      ctx.arc(this.mapOffsetX + (0.5 + this.player.x) * this.gridCellSize,
 | 
			
		||||
        this.mapOffsetY + (0.5 + this.player.y) * this.gridCellSize,
 | 
			
		||||
        this.gridCellSize / 2, 0, Math.PI * 2);
 | 
			
		||||
      ctx.fill();
 | 
			
		||||
      if (this.gameState == Maze_CTX2D.STATE_ENDED) {
 | 
			
		||||
        if (this.isFocused)
 | 
			
		||||
          this.drawBanner("Press space or enter to continue", "Victory!");
 | 
			
		||||
        ctx.lineWidth = 3;
 | 
			
		||||
        for (let p of this.fireworks) {
 | 
			
		||||
          ctx.strokeStyle = p.color;
 | 
			
		||||
          if (p.type >= 1) {
 | 
			
		||||
            ctx.beginPath();
 | 
			
		||||
            ctx.arc(p.x, p.y, p.size * 2, 0, Math.PI * 2);
 | 
			
		||||
            ctx.stroke();
 | 
			
		||||
          } else {
 | 
			
		||||
            ctx.beginPath();
 | 
			
		||||
            ctx.moveTo(p.x, p.y);
 | 
			
		||||
            ctx.lineTo(p.x + p.vx * 0.1, p.y + p.vy * 0.1);
 | 
			
		||||
            ctx.stroke();
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        ctx.lineWidth = 1;
 | 
			
		||||
        if (!this.isFocused)
 | 
			
		||||
          this.drawBanner("Click here to continue. (unfocused)", "Paused");
 | 
			
		||||
      }
 | 
			
		||||
      if (this.gameState == Maze_CTX2D.STATE_PLAYING) {
 | 
			
		||||
        if (!this.isFocused)
 | 
			
		||||
          this.drawBanner("Click here to continue. (unfocused)", "Paused");
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  drawBanner(innerText, titleText) {
 | 
			
		||||
    const ctx = this.ctx;
 | 
			
		||||
    const FONT_SIZE = this.width > 440 ? 24 : 16;
 | 
			
		||||
    const x = this.width / 2;
 | 
			
		||||
    const y = this.height / 2;
 | 
			
		||||
    const y2 = y - FONT_SIZE / 2;
 | 
			
		||||
    ctx.strokeStyle = 'black';
 | 
			
		||||
    const g = ctx.createLinearGradient(0, 0, this.width, 0);
 | 
			
		||||
    g.addColorStop(0, '#404040a0');
 | 
			
		||||
    g.addColorStop(0.2, '#404040df');
 | 
			
		||||
    g.addColorStop(0.8, '#404040df');
 | 
			
		||||
    g.addColorStop(1, '#404040a0');
 | 
			
		||||
    ctx.fillStyle = g;
 | 
			
		||||
    ctx.fillRect(0, y2 - 2, this.width + 1, FONT_SIZE + 5 * 2);
 | 
			
		||||
    ctx.strokeRect(0, y2 - 2, this.width + 1, FONT_SIZE + 5 * 2);
 | 
			
		||||
    if (typeof innerText === "string") {
 | 
			
		||||
      ctx.fillStyle = 'goldenrod';//this.isFocused ? 'goldenrod' : 'lightgray';
 | 
			
		||||
      ctx.font = FONT_SIZE + "px serif";
 | 
			
		||||
      ctx.strokeText(innerText, x, y2 + FONT_SIZE);
 | 
			
		||||
      ctx.fillText(innerText, x, y2 + FONT_SIZE);
 | 
			
		||||
    }
 | 
			
		||||
    if (typeof titleText === "string") {
 | 
			
		||||
      ctx.fillStyle = this.isFocused ? 'red' : 'gray';
 | 
			
		||||
      ctx.font = 4 * FONT_SIZE + "px serif";
 | 
			
		||||
      ctx.fillText(titleText, x, y - 2 * FONT_SIZE);
 | 
			
		||||
      ctx.strokeText(titleText, x, y - 2 * FONT_SIZE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  updateCanvas() {
 | 
			
		||||
    const now = performance.now();
 | 
			
		||||
    const timeDelta = (now - this.prevNow) / 1000; //timeDelta = (milli - milli) / toSeconds
 | 
			
		||||
    this.prevNow = now;
 | 
			
		||||
    //#state switch
 | 
			
		||||
    if (this.gameState == Maze_CTX2D.STATE_MAP_GEN_ANIM) {
 | 
			
		||||
      this.animationStepTime += timeDelta;
 | 
			
		||||
      while (this.animationStepTime >= this.animationStepDelay) {
 | 
			
		||||
        this.animationStepTime -= this.animationStepDelay;
 | 
			
		||||
        if (this.animationPos < this.animation.length) {
 | 
			
		||||
          this.animationPos++;
 | 
			
		||||
        } else {
 | 
			
		||||
          this.gameState = Maze_CTX2D.STATE_PLAYING;
 | 
			
		||||
          this.running = false;
 | 
			
		||||
          this.playSound(3);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else if (this.gameState == Maze_CTX2D.STATE_ENDED) {
 | 
			
		||||
      this.fireworksStepTime += timeDelta;
 | 
			
		||||
      if (this.fireworksStepTime > 3) {
 | 
			
		||||
        this.boom();
 | 
			
		||||
        this.fireworksStepTime = 0 + Math.random() * .5;
 | 
			
		||||
      }
 | 
			
		||||
      for (let p of this.fireworks) {
 | 
			
		||||
        p.time += timeDelta;
 | 
			
		||||
        if (p.time > 2) {
 | 
			
		||||
          p.time = 0;
 | 
			
		||||
          p.type += 1;
 | 
			
		||||
        }
 | 
			
		||||
        if (p.type == 0) {
 | 
			
		||||
          p.x += p.vx * timeDelta;
 | 
			
		||||
          p.y += p.vy * timeDelta;
 | 
			
		||||
        } else if (p.type == 1) {
 | 
			
		||||
          p.size += 10 * timeDelta;
 | 
			
		||||
        } else {
 | 
			
		||||
          p.size += timeDelta;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      while (this.fireworks.length > 0 && this.fireworks[0].type == 3) this.fireworks.shift();
 | 
			
		||||
    }
 | 
			
		||||
    this.drawCanvas();
 | 
			
		||||
    if (this.running) { // loop
 | 
			
		||||
      this.animationRequestId = requestAnimationFrame(() => this.updateCanvas());
 | 
			
		||||
    } else { // not looping
 | 
			
		||||
      this.animationRequestId = 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  startRunning(fn) {
 | 
			
		||||
    if (this.animationRequestId != 0) cancelAnimationFrame(this.animationRequestId);
 | 
			
		||||
    this.running = true;
 | 
			
		||||
    this.prevNow = performance.now();
 | 
			
		||||
    if (this.showFps) {
 | 
			
		||||
      this.initTime = performance.now();
 | 
			
		||||
    }
 | 
			
		||||
    this.animationRequestId = requestAnimationFrame(fn);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  close() {
 | 
			
		||||
    if (this.animationRequestId != 0) {
 | 
			
		||||
      cancelAnimationFrame(this.animationRequestId);
 | 
			
		||||
      this.animationRequestId = 0;
 | 
			
		||||
    }
 | 
			
		||||
    this.running = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pausePlayGame() {
 | 
			
		||||
    this.running = !this.running;
 | 
			
		||||
    if (this.running) {
 | 
			
		||||
      this.startRunning(() => this.updateCanvas());
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  terminalPrintGame(term) {
 | 
			
		||||
    term.printVar(this, "pong");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  terminalRestartGame(term) {
 | 
			
		||||
    term.terminalClose();
 | 
			
		||||
    this.restartGame();
 | 
			
		||||
    // this.canvasEl.focus();
 | 
			
		||||
    setTimeout(() => { this.canvasEl.focus(); this.pausePlayGame(); }, 200);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  setDifficulty(difficulty) {
 | 
			
		||||
    if (difficulty <= 0) difficulty = 0;
 | 
			
		||||
    this.difficulty = difficulty;
 | 
			
		||||
    this.gridWidth = 11 + 4 * this.difficulty;
 | 
			
		||||
    this.gridHeight = 11 + 4 * this.difficulty;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onKeyDown(e) {
 | 
			
		||||
    if (e.key == Maze_CTX2D.KEY_ESCAPE) {
 | 
			
		||||
      console.log('esc');
 | 
			
		||||
      console.log('running:', this.running);
 | 
			
		||||
      if (this.running) {
 | 
			
		||||
        this.pausePlayGame();
 | 
			
		||||
      } else {
 | 
			
		||||
        this.gameState = Maze_CTX2D.STATE_MENU;
 | 
			
		||||
        this.drawCanvas();
 | 
			
		||||
      }
 | 
			
		||||
      e.preventDefault();
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    switch (this.gameState) {
 | 
			
		||||
      case Maze_CTX2D.STATE_MENU:
 | 
			
		||||
        if (e.key == Maze_CTX2D.KEY_ENTER || e.key == Maze_CTX2D.KEY_SPACEBAR) {
 | 
			
		||||
          // console.log("ENTER!");
 | 
			
		||||
          this.newGame(this.gridWidth, this.gridHeight);
 | 
			
		||||
          this.gameState = Maze_CTX2D.STATE_MAP_GEN_ANIM;
 | 
			
		||||
          this.startRunning(() => this.updateCanvas());
 | 
			
		||||
          this.playSound(4);
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (e.key == Maze_CTX2D.KEY_S || e.key == Maze_CTX2D.KEY_ARROW_DOWN ||
 | 
			
		||||
          e.key == Maze_CTX2D.KEY_A || e.key == Maze_CTX2D.KEY_ARROW_LEFT) {
 | 
			
		||||
          this.setDifficulty(this.difficulty - 1);
 | 
			
		||||
          this.playSound(1);
 | 
			
		||||
          this.drawCanvas();
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (e.key == Maze_CTX2D.KEY_W || e.key == Maze_CTX2D.KEY_ARROW_UP ||
 | 
			
		||||
          e.key == Maze_CTX2D.KEY_D || e.key == Maze_CTX2D.KEY_ARROW_RIGHT) {
 | 
			
		||||
          this.setDifficulty(this.difficulty + 1);
 | 
			
		||||
          this.playSound(1);
 | 
			
		||||
          this.drawCanvas();
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case Maze_CTX2D.STATE_MAP_GEN_ANIM:
 | 
			
		||||
        if (e.key == Maze_CTX2D.KEY_ENTER || e.key == Maze_CTX2D.KEY_SPACEBAR) {
 | 
			
		||||
          if (this.running) {
 | 
			
		||||
            this.animationPos = this.animation.length;
 | 
			
		||||
          } else {
 | 
			
		||||
            this.startRunning(() => this.updateCanvas());
 | 
			
		||||
          }
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case Maze_CTX2D.STATE_PLAYING:
 | 
			
		||||
        if (e.key == 'r') {
 | 
			
		||||
          this.gameState = Maze_CTX2D.STATE_MAP_GEN_ANIM;
 | 
			
		||||
          this.animationPos = 0;
 | 
			
		||||
          this.animationStepTime = 0;
 | 
			
		||||
          this.startRunning(() => this.updateCanvas());
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (e.key == Maze_CTX2D.KEY_W || e.key == Maze_CTX2D.KEY_ARROW_UP) {
 | 
			
		||||
          if (this.player.y > 0) {
 | 
			
		||||
            if (this.maze[this.player.y - 1][this.player.x] == 0) {
 | 
			
		||||
              this.player.y -= 1;
 | 
			
		||||
              this.drawCanvas();
 | 
			
		||||
              this.playSound(1);
 | 
			
		||||
            } else {
 | 
			
		||||
              this.playSound(2);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (e.key == Maze_CTX2D.KEY_S || e.key == Maze_CTX2D.KEY_ARROW_DOWN) {
 | 
			
		||||
          if (this.player.y < this.gridHeight - 1) {
 | 
			
		||||
            if (this.maze[this.player.y + 1][this.player.x] == 0) {
 | 
			
		||||
              this.player.y += 1;
 | 
			
		||||
              if (this.player.y == this.gridHeight - 1) {
 | 
			
		||||
                this.gameState = Maze_CTX2D.STATE_ENDED;
 | 
			
		||||
                this.fireworks = [];
 | 
			
		||||
                this.fireworksStepTime = 0;
 | 
			
		||||
                this.boom();
 | 
			
		||||
                this.playSound(0);
 | 
			
		||||
                // this.drawCanvas();
 | 
			
		||||
                this.startRunning(() => this.updateCanvas())
 | 
			
		||||
              } else {
 | 
			
		||||
                this.drawCanvas();
 | 
			
		||||
              }
 | 
			
		||||
              this.playSound(1);
 | 
			
		||||
            } else {
 | 
			
		||||
              this.playSound(2);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (e.key == Maze_CTX2D.KEY_A || e.key == Maze_CTX2D.KEY_ARROW_LEFT) {
 | 
			
		||||
          if (this.player.x > 0) {
 | 
			
		||||
            if (this.maze[this.player.y][this.player.x - 1] == 0) {
 | 
			
		||||
              this.player.x -= 1;
 | 
			
		||||
              this.drawCanvas();
 | 
			
		||||
              this.playSound(1);
 | 
			
		||||
            } else {
 | 
			
		||||
              this.playSound(2);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (e.key == Maze_CTX2D.KEY_D || e.key == Maze_CTX2D.KEY_ARROW_RIGHT) {
 | 
			
		||||
          if (this.player.x < this.gridWidth) {
 | 
			
		||||
            if (this.maze[this.player.y][this.player.x + 1] == 0) {
 | 
			
		||||
              this.player.x += 1;
 | 
			
		||||
              this.drawCanvas();
 | 
			
		||||
              this.playSound(1);
 | 
			
		||||
            } else {
 | 
			
		||||
              this.playSound(2);
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case Maze_CTX2D.STATE_ENDED:
 | 
			
		||||
        if (e.key == Maze_CTX2D.KEY_ENTER || e.key == Maze_CTX2D.KEY_SPACEBAR) {
 | 
			
		||||
          this.gameState = Maze_CTX2D.STATE_MENU;
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    // if (e.key == Maze_CTX2D.KEY_ARROW_UP || e.key == Maze_CTX2D.KEY_W) {
 | 
			
		||||
    //   this.human.vy = -this.speedHuman;
 | 
			
		||||
    //   e.preventDefault();
 | 
			
		||||
    //   return false;
 | 
			
		||||
    // } else if (e.key == Maze_CTX2D.KEY_ARROW_DOWN || e.key == Maze_CTX2D.KEY_S) {
 | 
			
		||||
    //   this.human.vy = this.speedHuman;
 | 
			
		||||
    //   e.preventDefault();
 | 
			
		||||
    //   return false;
 | 
			
		||||
    // } else if (e.key == Maze_CTX2D.KEY_ENTER || e.key == Maze_CTX2D.KEY_SPACEBAR) {
 | 
			
		||||
    //   //# next round/pause/play
 | 
			
		||||
    //   if (this.gameState == Maze_CTX2D.STATE_ENDED) {
 | 
			
		||||
    //     this.newRound();
 | 
			
		||||
    //     this.startRunning(() => this.updateCanvas());
 | 
			
		||||
    //   } else {
 | 
			
		||||
    //     this.pausePlayGame();
 | 
			
		||||
    //   }
 | 
			
		||||
    //   e.preventDefault();
 | 
			
		||||
    //   return false;
 | 
			
		||||
    // }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onKeyUp(e) {
 | 
			
		||||
    // if (e.key == Maze_CTX2D.KEY_ARROW_UP || e.key == Maze_CTX2D.KEY_W) {
 | 
			
		||||
    //   this.human.vy = 0;
 | 
			
		||||
    //   e.preventDefault();
 | 
			
		||||
    //   return false;
 | 
			
		||||
    // } else if (e.key == Maze_CTX2D.KEY_ARROW_DOWN || e.key == Maze_CTX2D.KEY_S) {
 | 
			
		||||
    //   this.human.vy = 0;
 | 
			
		||||
    //   e.preventDefault();
 | 
			
		||||
    //   return false;
 | 
			
		||||
    // }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onBlur() {
 | 
			
		||||
    this.isFocused = false;
 | 
			
		||||
    this.canvasEl.style.borderColor = null;
 | 
			
		||||
    if (this.running) {
 | 
			
		||||
      this.pausePlayGame();
 | 
			
		||||
    } else {
 | 
			
		||||
      this.drawCanvas();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onFocus() {
 | 
			
		||||
    this.isFocused = true;
 | 
			
		||||
    this.canvasEl.style.borderColor = "red";
 | 
			
		||||
    if (!this.running && (Maze_CTX2D.AUTO_CONTINUE_ON_FOCUS
 | 
			
		||||
      || this.gameState == Maze_CTX2D.STATE_MAP_GEN_ANIM
 | 
			
		||||
      || this.gameState == Maze_CTX2D.STATE_ENDED)) {
 | 
			
		||||
      this.pausePlayGame();
 | 
			
		||||
    } else {
 | 
			
		||||
      this.drawCanvas();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  boom() {
 | 
			
		||||
    const colors = ['red', 'green', 'blue', 'violet', 'orange', 'goldenrod'];
 | 
			
		||||
    const color = colors[Math.floor(Math.random() * colors.length)];
 | 
			
		||||
 | 
			
		||||
    const cx = this.width / 2;
 | 
			
		||||
    const cy = this.height / 2;
 | 
			
		||||
    const speed = 100;
 | 
			
		||||
    const size = 10;
 | 
			
		||||
    const count = Math.random() < 0.75 ? 2 : 3;
 | 
			
		||||
    for (let i = 0; i < count; i++) {
 | 
			
		||||
      let p = {}
 | 
			
		||||
      p.x = cx;
 | 
			
		||||
      p.y = cy;
 | 
			
		||||
      let rot = Math.random() * Math.PI * .5 - 0.75 * Math.PI;
 | 
			
		||||
      p.vx = Math.cos(rot) * speed;
 | 
			
		||||
      p.vy = Math.sin(rot) * speed;
 | 
			
		||||
      p.type = 0;
 | 
			
		||||
      p.time = 0 + Math.random() * 0.5;
 | 
			
		||||
      p.size = size + Math.random() * 10;
 | 
			
		||||
      p.color = color;
 | 
			
		||||
      this.fireworks.push(p)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  generateBacktrackingMaze(width, height) {
 | 
			
		||||
 | 
			
		||||
    // Make them odd
 | 
			
		||||
    width -= width % 2; width++;
 | 
			
		||||
    height -= height % 2; height++;
 | 
			
		||||
 | 
			
		||||
    // Fill maze with 1's (walls)
 | 
			
		||||
    let maze = [];
 | 
			
		||||
    for (let i = 0; i < height; i++) {
 | 
			
		||||
      maze.push([]);
 | 
			
		||||
      for (let j = 0; j < width; j++) {
 | 
			
		||||
        maze[i].push(1);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let anim = [];
 | 
			
		||||
 | 
			
		||||
    // Opening at top - start of maze
 | 
			
		||||
    maze[0][1] = 0;
 | 
			
		||||
 | 
			
		||||
    let start = [];
 | 
			
		||||
    do {
 | 
			
		||||
      start[0] = Math.floor(Math.random() * height)
 | 
			
		||||
    } while (start[0] % 2 == 0);
 | 
			
		||||
    do {
 | 
			
		||||
      start[1] = Math.floor(Math.random() * width)
 | 
			
		||||
    } while (start[1] % 2 == 0);
 | 
			
		||||
 | 
			
		||||
    maze[start[0]][start[1]] = 0;
 | 
			
		||||
    anim.push({ state: 1, x: start[1], y: start[0] });
 | 
			
		||||
 | 
			
		||||
    // First open cell
 | 
			
		||||
    let openCells = [start];
 | 
			
		||||
 | 
			
		||||
    while (openCells.length) {
 | 
			
		||||
 | 
			
		||||
      let cell, n;
 | 
			
		||||
 | 
			
		||||
      // Add unnecessary element for elegance of code
 | 
			
		||||
      // Allows openCells.pop() at beginning of do while loop
 | 
			
		||||
      openCells.push([-1, -1]);
 | 
			
		||||
 | 
			
		||||
      // Define current cell as last element in openCells
 | 
			
		||||
      // and get neighbors, discarding "locked" cells
 | 
			
		||||
      do {
 | 
			
		||||
        let step = openCells.pop();
 | 
			
		||||
        if (step[0] > 0 && step[1] > 0) anim.push({ state: 0, x: step[1], y: step[0] });
 | 
			
		||||
        if (openCells.length == 0)
 | 
			
		||||
          break;
 | 
			
		||||
        cell = openCells[openCells.length - 1];
 | 
			
		||||
        n = this.getMazeNeighbors(maze, cell[0], cell[1]);
 | 
			
		||||
      } while (n.length == 0 && openCells.length > 0);
 | 
			
		||||
 | 
			
		||||
      // If we're done, don't bother continuing
 | 
			
		||||
      if (openCells.length == 0)
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      // Choose random neighbor and add it to openCells
 | 
			
		||||
      let choice = n[Math.floor(Math.random() * n.length)];
 | 
			
		||||
      openCells.push(choice);
 | 
			
		||||
 | 
			
		||||
      // Set neighbor to 0 (path, not wall)
 | 
			
		||||
      // Set connecting node between cell and choice to 0
 | 
			
		||||
      let connectY = (choice[0] + cell[0]) / 2;
 | 
			
		||||
      let connectX = (choice[1] + cell[1]) / 2;
 | 
			
		||||
      maze[choice[0]][choice[1]] = 0;
 | 
			
		||||
      maze[connectY][connectX] = 0;
 | 
			
		||||
      anim.push({ state: 0, x: connectX, y: connectY });
 | 
			
		||||
      anim.push({ state: 1, x: choice[1], y: choice[0] });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Opening at bottom - end of maze
 | 
			
		||||
    maze[maze.length - 1][maze[0].length - 2] = 0;
 | 
			
		||||
    // maze[maze.length - 2][maze[0].length - 2] = 0;
 | 
			
		||||
    anim.push({ state: 0, x: maze[0].length - 2, y: maze.length - 1 });
 | 
			
		||||
    // anim.push({ state: 0, x: maze[0].length - 1, y: maze.length - 1 });
 | 
			
		||||
 | 
			
		||||
    return { maze: maze, animation: anim };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getMazeNeighbors(maze, ic, jc) {
 | 
			
		||||
    let final = [];
 | 
			
		||||
    for (let i = 0; i < 4; i++) {
 | 
			
		||||
      let n = [ic, jc];
 | 
			
		||||
 | 
			
		||||
      // Iterates through four neighbors
 | 
			
		||||
      // [i][j - 2] 
 | 
			
		||||
      // [i][j + 2]
 | 
			
		||||
      // [i - 2][j]
 | 
			
		||||
      // [i + 2][j]
 | 
			
		||||
      n[i % 2] += ((Math.floor(i / 2) * 2) || -2);
 | 
			
		||||
      if (n[0] < maze.length &&
 | 
			
		||||
        n[1] < maze[0].length &&
 | 
			
		||||
        n[0] > 0 &&
 | 
			
		||||
        n[1] > 0) {
 | 
			
		||||
 | 
			
		||||
        if (maze[n[0]][n[1]] == 1) {
 | 
			
		||||
          final.push(n);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return final;
 | 
			
		||||
  }
 | 
			
		||||
}//-> class Maze_CTX2D
 | 
			
		||||
 | 
			
		||||
function startMaze(divId, width = 480, height = 320, difficulty = 1, showFps = true) {
 | 
			
		||||
  return new Maze_CTX2D(divId, width, height, difficulty, showFps);
 | 
			
		||||
}
 | 
			
		||||
@@ -41,6 +41,8 @@ class PingPong_CTX2D {
 | 
			
		||||
    this.audioCtx.createMediaElementSource(this.sounds[0]).connect(this.audioCtx.destination);
 | 
			
		||||
    this.sounds[1] = new Audio('./snd/short-success.mp3');
 | 
			
		||||
    this.audioCtx.createMediaElementSource(this.sounds[1]).connect(this.audioCtx.destination);
 | 
			
		||||
    this.sounds[2] = new Audio('./snd/flash.mp3');
 | 
			
		||||
    this.audioCtx.createMediaElementSource(this.sounds[2]).connect(this.audioCtx.destination);
 | 
			
		||||
 | 
			
		||||
    this.showFps = showFps;
 | 
			
		||||
    if (showFps) {
 | 
			
		||||
@@ -255,6 +257,7 @@ class PingPong_CTX2D {
 | 
			
		||||
      this.countDown -= timeDelta;//PONG_UPDATE_INTERVAL;
 | 
			
		||||
      if (this.countDown < 0) {
 | 
			
		||||
        this.gameState = PingPong_CTX2D.STATE_PLAYING;
 | 
			
		||||
        this.playSound(2);
 | 
			
		||||
      }
 | 
			
		||||
    } else if (this.gameState == PingPong_CTX2D.STATE_PLAYING) {
 | 
			
		||||
      //cpu actions
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@ class GamesLauncher {
 | 
			
		||||
    this.selectGameEl = createElement('select', { id: 'games', style: 'float: right;' });
 | 
			
		||||
    this.selectGameEl.appendChild(createElement('option', { value: 'pong-context2d' }, 'Pingpong (Context2D)'));
 | 
			
		||||
    this.selectGameEl.appendChild(createElement('option', { value: 'tetris-context2d' }, 'Tetris (Context2D)'));
 | 
			
		||||
    this.selectGameEl.appendChild(createElement('option', { value: 'maze-context2d' }, 'Maze (Context2D)'));
 | 
			
		||||
    this.selectGameEl.onchange = () => this.onSelectGameChange();
 | 
			
		||||
    this.gameEl.appendChild(this.selectGameEl);
 | 
			
		||||
    this.gameEl.appendChild(createElement('br'));
 | 
			
		||||
@@ -93,6 +94,11 @@ class GamesLauncher {
 | 
			
		||||
        this.heightEl.value = 600;
 | 
			
		||||
        // this.difficultyEl.value = 1;
 | 
			
		||||
        break;
 | 
			
		||||
      case 'maze-context2d':
 | 
			
		||||
        this.widthEl.value = 800;
 | 
			
		||||
        this.heightEl.value = 640;
 | 
			
		||||
        // this.difficultyEl.value = 1;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -113,6 +119,11 @@ class GamesLauncher {
 | 
			
		||||
        this.currentGame = new Tetris_CTX2D(this.gameId, width, height, difficulty, showFps);
 | 
			
		||||
        this.currentGame.canvasEl.focus();
 | 
			
		||||
        break;
 | 
			
		||||
      case 'maze-context2d':
 | 
			
		||||
        this.createCloseExitGameButton();
 | 
			
		||||
        this.currentGame = new Maze_CTX2D(this.gameId, width, height, difficulty, showFps);
 | 
			
		||||
        this.currentGame.canvasEl.focus();
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        alert("Select a game first?");
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ function toggleTheme() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function setTheme(themeName) {
 | 
			
		||||
  console.log("setting them: " + themeName);
 | 
			
		||||
  console.log("setting theme: " + themeName);
 | 
			
		||||
  const root = document.querySelector(":root");
 | 
			
		||||
  root.classList.add(themeName);
 | 
			
		||||
  localStorage.setItem('theme', themeName);
 | 
			
		||||
 
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								src/snd/flash.mp3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/snd/flash.mp3
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								src/snd/footstep.mp3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/snd/footstep.mp3
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								src/snd/metronome.mp3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/snd/metronome.mp3
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								src/snd/snap.mp3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/snd/snap.mp3
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								src/snd/surprise.mp3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/snd/surprise.mp3
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Reference in New Issue
	
	Block a user