diff --git a/home.png b/home.png new file mode 100644 index 0000000..6a0ffbf Binary files /dev/null and b/home.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..2be23e8 --- /dev/null +++ b/index.html @@ -0,0 +1,51 @@ + + + + + + + Maze + + + + +
+ +
+
+

Congratulations!

+

You are done.

+

+ +
+
+ +
+ + +
+
+ +
+
+ +

Use arrow keys to move the key to the house!

+ +
+ + + + + + + \ No newline at end of file diff --git a/key.png b/key.png new file mode 100644 index 0000000..dec26bb Binary files /dev/null and b/key.png differ diff --git a/script.js b/script.js new file mode 100644 index 0000000..9f614de --- /dev/null +++ b/script.js @@ -0,0 +1,585 @@ +function rand(max) { + return Math.floor(Math.random() * max); + } + + function shuffle(a) { + for (let i = a.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [a[i], a[j]] = [a[j], a[i]]; + } + return a; + } + + function changeBrightness(factor, sprite) { + var virtCanvas = document.createElement("canvas"); + virtCanvas.width = 500; + virtCanvas.height = 500; + var context = virtCanvas.getContext("2d"); + context.drawImage(sprite, 0, 0, 500, 500); + + var imgData = context.getImageData(0, 0, 500, 500); + + for (let i = 0; i < imgData.data.length; i += 4) { + imgData.data[i] = imgData.data[i] * factor; + imgData.data[i + 1] = imgData.data[i + 1] * factor; + imgData.data[i + 2] = imgData.data[i + 2] * factor; + } + context.putImageData(imgData, 0, 0); + + var spriteOutput = new Image(); + spriteOutput.src = virtCanvas.toDataURL(); + virtCanvas.remove(); + return spriteOutput; + } + + function displayVictoryMess(moves) { + document.getElementById("moves").innerHTML = "You Moved " + moves + " Steps."; + toggleVisablity("Message-Container"); + } + + function toggleVisablity(id) { + if (document.getElementById(id).style.visibility == "visible") { + document.getElementById(id).style.visibility = "hidden"; + } else { + document.getElementById(id).style.visibility = "visible"; + } + } + + function Maze(Width, Height) { + var mazeMap; + var width = Width; + var height = Height; + var startCoord, endCoord; + var dirs = ["n", "s", "e", "w"]; + var modDir = { + n: { + y: -1, + x: 0, + o: "s" + }, + s: { + y: 1, + x: 0, + o: "n" + }, + e: { + y: 0, + x: 1, + o: "w" + }, + w: { + y: 0, + x: -1, + o: "e" + } + }; + + this.map = function() { + return mazeMap; + }; + this.startCoord = function() { + return startCoord; + }; + this.endCoord = function() { + return endCoord; + }; + + function genMap() { + mazeMap = new Array(height); + for (y = 0; y < height; y++) { + mazeMap[y] = new Array(width); + for (x = 0; x < width; ++x) { + mazeMap[y][x] = { + n: false, + s: false, + e: false, + w: false, + visited: false, + priorPos: null + }; + } + } + } + + function defineMaze() { + var isComp = false; + var move = false; + var cellsVisited = 1; + var numLoops = 0; + var maxLoops = 0; + var pos = { + x: 0, + y: 0 + }; + var numCells = width * height; + while (!isComp) { + move = false; + mazeMap[pos.x][pos.y].visited = true; + + if (numLoops >= maxLoops) { + shuffle(dirs); + maxLoops = Math.round(rand(height / 8)); + numLoops = 0; + } + numLoops++; + for (index = 0; index < dirs.length; index++) { + var direction = dirs[index]; + var nx = pos.x + modDir[direction].x; + var ny = pos.y + modDir[direction].y; + + if (nx >= 0 && nx < width && ny >= 0 && ny < height) { + //Check if the tile is already visited + if (!mazeMap[nx][ny].visited) { + //Carve through walls from this tile to next + mazeMap[pos.x][pos.y][direction] = true; + mazeMap[nx][ny][modDir[direction].o] = true; + + //Set Currentcell as next cells Prior visited + mazeMap[nx][ny].priorPos = pos; + //Update Cell position to newly visited location + pos = { + x: nx, + y: ny + }; + cellsVisited++; + //Recursively call this method on the next tile + move = true; + break; + } + } + } + + if (!move) { + // If it failed to find a direction, + // move the current position back to the prior cell and Recall the method. + pos = mazeMap[pos.x][pos.y].priorPos; + } + if (numCells == cellsVisited) { + isComp = true; + } + } + } + + function defineStartEnd() { + switch (rand(4)) { + case 0: + startCoord = { + x: 0, + y: 0 + }; + endCoord = { + x: height - 1, + y: width - 1 + }; + break; + case 1: + startCoord = { + x: 0, + y: width - 1 + }; + endCoord = { + x: height - 1, + y: 0 + }; + break; + case 2: + startCoord = { + x: height - 1, + y: 0 + }; + endCoord = { + x: 0, + y: width - 1 + }; + break; + case 3: + startCoord = { + x: height - 1, + y: width - 1 + }; + endCoord = { + x: 0, + y: 0 + }; + break; + } + } + + genMap(); + defineStartEnd(); + defineMaze(); + } + + function DrawMaze(Maze, ctx, cellsize, endSprite = null) { + var map = Maze.map(); + var cellSize = cellsize; + var drawEndMethod; + ctx.lineWidth = cellSize / 40; + + this.redrawMaze = function(size) { + cellSize = size; + ctx.lineWidth = cellSize / 50; + drawMap(); + drawEndMethod(); + }; + + function drawCell(xCord, yCord, cell) { + var x = xCord * cellSize; + var y = yCord * cellSize; + + if (cell.n == false) { + ctx.beginPath(); + ctx.moveTo(x, y); + ctx.lineTo(x + cellSize, y); + ctx.stroke(); + } + if (cell.s === false) { + ctx.beginPath(); + ctx.moveTo(x, y + cellSize); + ctx.lineTo(x + cellSize, y + cellSize); + ctx.stroke(); + } + if (cell.e === false) { + ctx.beginPath(); + ctx.moveTo(x + cellSize, y); + ctx.lineTo(x + cellSize, y + cellSize); + ctx.stroke(); + } + if (cell.w === false) { + ctx.beginPath(); + ctx.moveTo(x, y); + ctx.lineTo(x, y + cellSize); + ctx.stroke(); + } + } + + function drawMap() { + for (x = 0; x < map.length; x++) { + for (y = 0; y < map[x].length; y++) { + drawCell(x, y, map[x][y]); + } + } + } + + function drawEndFlag() { + var coord = Maze.endCoord(); + var gridSize = 4; + var fraction = cellSize / gridSize - 2; + var colorSwap = true; + for (let y = 0; y < gridSize; y++) { + if (gridSize % 2 == 0) { + colorSwap = !colorSwap; + } + for (let x = 0; x < gridSize; x++) { + ctx.beginPath(); + ctx.rect( + coord.x * cellSize + x * fraction + 4.5, + coord.y * cellSize + y * fraction + 4.5, + fraction, + fraction + ); + if (colorSwap) { + ctx.fillStyle = "rgba(0, 0, 0, 0.8)"; + } else { + ctx.fillStyle = "rgba(255, 255, 255, 0.8)"; + } + ctx.fill(); + colorSwap = !colorSwap; + } + } + } + + function drawEndSprite() { + var offsetLeft = cellSize / 50; + var offsetRight = cellSize / 25; + var coord = Maze.endCoord(); + ctx.drawImage( + endSprite, + 2, + 2, + endSprite.width, + endSprite.height, + coord.x * cellSize + offsetLeft, + coord.y * cellSize + offsetLeft, + cellSize - offsetRight, + cellSize - offsetRight + ); + } + + function clear() { + var canvasSize = cellSize * map.length; + ctx.clearRect(0, 0, canvasSize, canvasSize); + } + + if (endSprite != null) { + drawEndMethod = drawEndSprite; + } else { + drawEndMethod = drawEndFlag; + } + clear(); + drawMap(); + drawEndMethod(); + } + + function Player(maze, c, _cellsize, onComplete, sprite = null) { + var ctx = c.getContext("2d"); + var drawSprite; + var moves = 0; + drawSprite = drawSpriteCircle; + if (sprite != null) { + drawSprite = drawSpriteImg; + } + var player = this; + var map = maze.map(); + var cellCoords = { + x: maze.startCoord().x, + y: maze.startCoord().y + }; + var cellSize = _cellsize; + var halfCellSize = cellSize / 2; + + this.redrawPlayer = function(_cellsize) { + cellSize = _cellsize; + drawSpriteImg(cellCoords); + }; + + function drawSpriteCircle(coord) { + ctx.beginPath(); + ctx.fillStyle = "yellow"; + ctx.arc( + (coord.x + 1) * cellSize - halfCellSize, + (coord.y + 1) * cellSize - halfCellSize, + halfCellSize - 2, + 0, + 2 * Math.PI + ); + ctx.fill(); + if (coord.x === maze.endCoord().x && coord.y === maze.endCoord().y) { + onComplete(moves); + player.unbindKeyDown(); + } + } + + function drawSpriteImg(coord) { + var offsetLeft = cellSize / 50; + var offsetRight = cellSize / 25; + ctx.drawImage( + sprite, + 0, + 0, + sprite.width, + sprite.height, + coord.x * cellSize + offsetLeft, + coord.y * cellSize + offsetLeft, + cellSize - offsetRight, + cellSize - offsetRight + ); + if (coord.x === maze.endCoord().x && coord.y === maze.endCoord().y) { + onComplete(moves); + player.unbindKeyDown(); + } + } + + function removeSprite(coord) { + var offsetLeft = cellSize / 50; + var offsetRight = cellSize / 25; + ctx.clearRect( + coord.x * cellSize + offsetLeft, + coord.y * cellSize + offsetLeft, + cellSize - offsetRight, + cellSize - offsetRight + ); + } + + function check(e) { + var cell = map[cellCoords.x][cellCoords.y]; + moves++; + switch (e.keyCode) { + case 65: + case 37: // west + if (cell.w == true) { + removeSprite(cellCoords); + cellCoords = { + x: cellCoords.x - 1, + y: cellCoords.y + }; + drawSprite(cellCoords); + } + break; + case 87: + case 38: // north + if (cell.n == true) { + removeSprite(cellCoords); + cellCoords = { + x: cellCoords.x, + y: cellCoords.y - 1 + }; + drawSprite(cellCoords); + } + break; + case 68: + case 39: // east + if (cell.e == true) { + removeSprite(cellCoords); + cellCoords = { + x: cellCoords.x + 1, + y: cellCoords.y + }; + drawSprite(cellCoords); + } + break; + case 83: + case 40: // south + if (cell.s == true) { + removeSprite(cellCoords); + cellCoords = { + x: cellCoords.x, + y: cellCoords.y + 1 + }; + drawSprite(cellCoords); + } + break; + } + } + + this.bindKeyDown = function() { + window.addEventListener("keydown", check, false); + + $("#view").swipe({ + swipe: function( + event, + direction, + distance, + duration, + fingerCount, + fingerData + ) { + console.log(direction); + switch (direction) { + case "up": + check({ + keyCode: 38 + }); + break; + case "down": + check({ + keyCode: 40 + }); + break; + case "left": + check({ + keyCode: 37 + }); + break; + case "right": + check({ + keyCode: 39 + }); + break; + } + }, + threshold: 0 + }); + }; + + this.unbindKeyDown = function() { + window.removeEventListener("keydown", check, false); + $("#view").swipe("destroy"); + }; + + drawSprite(maze.startCoord()); + + this.bindKeyDown(); + } + + var mazeCanvas = document.getElementById("mazeCanvas"); + var ctx = mazeCanvas.getContext("2d"); + var sprite; + var finishSprite; + var maze, draw, player; + var cellSize; + var difficulty; + // sprite.src = 'media/sprite.png'; + + window.onload = function() { + let viewWidth = $("#view").width(); + let viewHeight = $("#view").height(); + if (viewHeight < viewWidth) { + ctx.canvas.width = viewHeight - viewHeight / 100; + ctx.canvas.height = viewHeight - viewHeight / 100; + } else { + ctx.canvas.width = viewWidth - viewWidth / 100; + ctx.canvas.height = viewWidth - viewWidth / 100; + } + + //Load and edit sprites + var completeOne = false; + var completeTwo = false; + var isComplete = () => { + if(completeOne === true && completeTwo === true) + { + console.log("Runs"); + setTimeout(function(){ + makeMaze(); + }, 500); + } + }; + sprite = new Image(); + sprite.src = + "./key.png" + + "?" + + new Date().getTime(); + sprite.setAttribute("crossOrigin", " "); + sprite.onload = function() { + sprite = changeBrightness(1.2, sprite); + completeOne = true; + console.log(completeOne); + isComplete(); + }; + + finishSprite = new Image(); + finishSprite.src = "./home.png"+ + "?" + + new Date().getTime(); + finishSprite.setAttribute("crossOrigin", " "); + finishSprite.onload = function() { + finishSprite = changeBrightness(1.1, finishSprite); + completeTwo = true; + console.log(completeTwo); + isComplete(); + }; + + }; + + window.onresize = function() { + let viewWidth = $("#view").width(); + let viewHeight = $("#view").height(); + if (viewHeight < viewWidth) { + ctx.canvas.width = viewHeight - viewHeight / 100; + ctx.canvas.height = viewHeight - viewHeight / 100; + } else { + ctx.canvas.width = viewWidth - viewWidth / 100; + ctx.canvas.height = viewWidth - viewWidth / 100; + } + cellSize = mazeCanvas.width / difficulty; + if (player != null) { + draw.redrawMaze(cellSize); + player.redrawPlayer(cellSize); + } + }; + + function makeMaze() { + if (player != undefined) { + player.unbindKeyDown(); + player = null; + } + var e = document.getElementById("diffSelect"); + difficulty = e.options[e.selectedIndex].value; + cellSize = mazeCanvas.width / difficulty; + maze = new Maze(difficulty, difficulty); + draw = new DrawMaze(maze, ctx, cellSize, finishSprite); + player = new Player(maze, mazeCanvas, cellSize, displayVictoryMess, sprite); + if (document.getElementById("mazeContainer").style.opacity < "100") { + document.getElementById("mazeContainer").style.opacity = "100"; + } + } diff --git a/style.css b/style.css new file mode 100644 index 0000000..dee9291 --- /dev/null +++ b/style.css @@ -0,0 +1,132 @@ +@import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap'); + +html, body { + width: 100vw; + height: 100vh; + position: fixed; + padding: 0; + margin: 0; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: #fff; + font-family: 'Poppins', sans-serif; +} + +#view { + margin-top: 30px; +} + +#mazeContainer { + top: 15px; + opacity: 0; + display: inline-block; + margin: auto; + border-radius: 10px; +} +#mazeContainer #mazeCanvas { + margin: 0; + display: block; + border: solid 2px black; + height: 400px; +} +input, select { + cursor: pointer; + background-color: rgba(0, 0, 0, 0.30); + height: 45px; + width: 150px; + padding: 10px; + border: none; + border-radius: 5px; + color: white; + display: inline-block; + font-size: 15px; + text-align: center; + text-decoration: none; + appearance: none; +} +input:hover, select:hover { + background-color: rgba(0, 0, 0, 0.70); +} +input:active, select:active { + background-color: black; +} +input:focus, select:focus { + outline: none; +} +.custom-select { + display: inline-block; +} +.custom-select select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-repeat: no-repeat; + background-position: 125px center; +} +#Message-Container { + visibility: hidden; + color: white; + display: block; + width: 100vw; + height: 100vh; + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + background-color: rgba(0, 0, 0, 0.30); + z-index: 1; +} +#Message-Container #message { + width: 300px; + height: 300px; + position: fixed; + top: 50%; + left: 50%; + margin-left: -150px; + margin-top: -150px; +} +#page { + text-align: center; + height: auto; + width: auto; + margin: auto; +} +#page #menu { + margin: auto; + padding: 10px; + height: 65px; + box-sizing: border-box; +} +#page #menu h1 { + margin: 0; + margin-bottom: 10px; + font-weight: 600; + font-size: 3.2rem; +} +#page #view { + position: absolute; + top: 65px; + bottom: 0; + left: 0; + right: 0; + width: 100%; + height: auto; +} +.border { + border: 10px black solid; + border-radius: 10px; +} + +#instructions { + margin-top: 425px; +} + +/* Extra small devices (phones, 600px and down) */ +@media only screen and (max-width: 400px) { + input, select { + width: 120px; + } +} \ No newline at end of file