Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>Document</title>
- <style>
- html,
- body {
- height: 90%
- }
- </style>
- </head>
- <body>
- <div style="display:none">
- <svg class="block" version="1.1" viewBox="0 0 10.26 10.26" preserveAspectRatio="none"
- xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#"
- xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
- <g transform="translate(-3.4688 -2.8125)">
- <g stroke="#000" stroke-linecap="square">
- <rect x="3.9688" y="3.3125" width="9.2604" height="9.2604" fill="#b3b3b3"
- style="paint-order:stroke fill markers" />
- <rect x="5.2917" y="4.6354" width="6.6146" height="6.6146" fill="#333" stroke-width=".5"
- style="paint-order:stroke fill markers" />
- <rect x="6.6146" y="5.9583" width="3.9688" height="3.9688" fill="#f2f2f2" stroke-width=".5"
- style="paint-order:stroke fill markers" />
- </g>
- <path d="m13.229 3.3125h-9.2604v9.2604z" fill="#ffe6d5" fill-rule="evenodd" opacity=".515" />
- <path d="m13.229 12.573h-9.2604v-9.2604z" fill="#280b0b" fill-rule="evenodd" opacity=".515" />
- </g>
- </svg>
- <img class="block" />
- <img class="back"
- src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQBAMAAABykSv/AAAAFVBMVEX////6+vr9/f3+/v77+/v8/Pz5+fnUxEs+AAAD2klEQVR4Xu3cMW4UQRSE4ScbDrC7NvFgOMCCIAfsAxhxAu5/CYhcoJ7FTdbP+l5aqqCk1iTz66/vh/27bRbU6wvJY7Og6u1ucGwX1NVusrUL9jce+wX7G7d2wf7GY79gf+PWMhg3HnsG48ataVD14a/g1DMYN27tgtz7Q+5bz2DcuLUMxi/BsXVQ10/JuXWQL8Gpd5CN59ZBNp56B9l4bhvkPv0O7hsH2fj1cHNuHWTjfesg93Bh4fVDg8bdH/euLtzHu+FWa9Qh9/N8qXL95pBbs5Eh+Qbsvsfcmo0MyTdg/xORW7JRw/Rnx6/ZqGH6s+PXbGTIl/rnvcqAFRsZclPPXMYv2ahMr8nxazYq02fHr9moTJ8dv2ajMn12/IKNDPkxU/mcGWs1MuS2Zi4/ThdsVN7i7Htcs1F5i7Pvcb3G05DHyUb+Za/XqLzF2fe4ZqMyfXb8mo3K9NnxazYq02fHr9moTJ8dv2ajMn12/JqNyvTZ8Ws2avvfytWajXox9/IJOgQdgg5Bh6BD0CHoEHQIOgQdgg5Bh6BD0CHoEHQIOgRdT1BubDQF5cZGT1BubDQF5cZGT1BubDQF5cZGT1BubPQG5dJoDsql0RuUS6M5KJdGb1AujeagXBq9Qbk0moNyafQG5dJoDsql0RuUS6M5KJdGb1AujeagXBq9Qbk0moNyaXQH5dLoD8ql0R+U22rVQ9Ah6BB0CDoEHYIOQYegQ9Ah6BB0CDoEHYIOQYegQ9Ah6DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46BB0CDoEHYIOQYegQ9Ah6BB0CDoEHYIOQYegQ9Ah6BB0CDoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoEHYIOQYegQ9Ah6BB0CDoEHYIOQYegQ9Ah6BB0CDoEHYKOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoMOQYegQ9Ah6BB0CDoEHYIOQYegQ9Ah6BB0CDoEHYIOQYeg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOgQ9Ah6BB0CDoEHYIOQYegQ9Ah6BB0CDoEHYIOQYegQ9Ah6DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46BB0CDoEHYIOQYegQ9Ah6BB0CDoEHYIOQYegQ9Ah6BB0CDoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DjoOOg46DrpfMHoHl1WY49wAAAAASUVORK5CYII=" />
- <!--background image 400*400px-->
- <audio class='shuffle' src="shuffle2.wav" preload="auto" controls="none"></audio>
- <!-- https://freesound.org/s/159355/ modified-->
- <audio class='down' src="shuffle3.wav" preload="auto" controls="none"></audio> <!-- also, modified -->
- <audio class='gameover' src="gameover.wav" preload="auto" controls="none"></audio>
- <!-- https://freesound.org/s/382310/ -->
- <audio class='clean' src="clean2.wav" preload="auto" controls="none"></audio>
- <!-- https://freesound.org/s/447808/ -->
- <audio class='background' src="NiGiD_-_Waiting_for_the_morning_bus.mp3" controls="none" autoplay loop></audio>
- <!-- http://dig.ccmixter.org/files/NiGiD/47862 -->
- </div>
- <canvas id="canvas" width=600 height=750></canvas>
- <div>
- <h3>Music Credits</h3>
- <ul>
- <li> Background: Waiting for the morning bus by Martijn de Boer (NiGiD) (c) copyright 2014 Licensed under a
- Creative Commons Attribution Noncommercial (3.0) license. http://dig.ccmixter.org/files/NiGiD/47862 Ft:
- Pitx</li>
- <li> sfx shuffle: https://freesound.org/s/159355/ </li>
- <li> sfx down: https://freesound.org/s/263001/</li>
- <li> sfx clean: https://freesound.org/s/447808/</li>
- </ul>
- </div>
- <script>
- (function () { //prevent simple console access from browser... like "score=1234567"
- var whitePx =
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==";
- var canvas; //canvas object
- var ctx; //canvas 2d context
- var lastsec; //drop 1 per sec
- var size; //size of canvas in px and grids
- var pixels; //dropping form
- var grid; //dropped forms
- var img_block, img_back; //image resources
- var audio_shuffle, audio_down, audio_gameover, audio_background, audio_clean; //audio resources
- var deleting, ending, paused, starting; //if false no dropping
- var score; //your archieved score.
- var rewards = [10, 30, 50, 70]; //bonus points for erased lines (4l = +70)
- var pausebounds; //boundaries for pause button
- var startbounds; //boundaries for start button
- var mx, my; //mouse xy
- var nextFormInd; //preview of next form
- var playSFX = true,
- playMusic = true; //flag for playing sfx sound
- var sidewidth; //width of sidebar
- var gradients = []; //gradients used at rendering. prerendered to save cpu
- var curForm = {
- x: [],
- y: []
- }; //current form
- var zwiForm = {
- x: [],
- y: []
- }; //turned form used at turning pieces
- var forms = [{ //possivle forms
- x: [-1, 0, 1, 2], //I
- y: [0, 0, 0, 0],
- w: 4,
- h: 1
- },
- {
- x: [-1, 0, 0, 1], //T
- y: [0, 0, 1, 0],
- w: 3,
- h: 2
- },
- {
- x: [-1, -1, 0, 0], //O
- y: [0, 1, 0, 1],
- w: 2,
- h: 2
- },
- {
- x: [-1, 0, 1, 1], //L
- y: [0, 0, 0, 1],
- w: 3,
- h: 2
- },
- {
- x: [-1, -1, 0, 1], //L rev
- y: [1, 0, 0, 0],
- w: 3,
- h: 2
- },
- {
- x: [-1, 0, 0, 1], //Z
- y: [1, 1, 0, 0],
- w: 3,
- h: 2
- },
- {
- x: [-1, 0, 0, 1], //Z rev
- y: [0, 0, 1, 1],
- w: 3,
- h: 2
- }
- ];
- var turn = [ //rotation matrix 90deg left
- [0, -1],
- [1, 0]
- ];
- function init() { //at start of each game.
- lastsec = 0;
- size = { //grid width/height in blocks
- w: 8,
- h: 14
- };
- grid = new Array(size.h + 1); //create 0 filles grid
- for (var i = 0; i < size.h + 1; ++i) {
- grid[i] = new Array(size.w + 1);
- grid[i].fill(0);
- }
- pixels = []; //moving blocks
- for (var i = 0; i < 4; ++i) //4 block pieces, initialies at top-center
- pixels.push({
- x: Math.ceil(size.w / 2.0),
- y: 0
- });
- canvas = document.getElementById('canvas');
- ctx = canvas.getContext('2d'); //get context for rendering
- rescale(); //adapt screen size
- //audio handles to play on demand
- audio_shuffle = document.querySelector("audio.shuffle");
- audio_down = document.querySelector("audio.down");
- audio_gameover = document.querySelector("audio.gameover");
- audio_clean = document.querySelector("audio.clean");
- audio_background = document.querySelector("audio.background");
- audio_background.volume = 0.2;
- if (playMusic) audio_background.play();
- //initialize flags
- pausehover = false; //not hovering over pause button
- deleting = false; //no line deleting animation atm
- ending = false; //game is not ending (animation)
- paused = false; //game is not paused (pause text)
- starting = true; //game is starting (splash screen)
- score = 0; //initial score 0
- nextFormInd = getRandomInt(forms.length); //next form coming down
- newPixel(false); //create form at top, no dropping yet
- }
- function rescale() { //adapt to screen size
- var sBarWPerc = 0.2; //20% of width is sidebar
- var scale = size.w / size.h / (1 - sBarWPerc); //block ratio rendered 1:1. Add sidebar
- canvas.height = canvas.parentElement.clientHeight; //canvas Height 100% of parent
- canvas.width = scale * canvas.height; //width rescale to keep aspect ratio
- //calculate current metrics from canvas-height and grid-size
- size.bw = Math.floor(canvas.clientWidth * (1 - sBarWPerc) / (size.w)); //bw=block with in px
- size.bh = Math.floor(canvas.clientHeight / (size.h + 1));
- size.ph = Math.floor(size.bh * (size.h + 1)); //ph = total height in pixel
- size.pw = Math.floor(size.bw * (size.w));
- sidewidth = canvas.clientWidth * (sBarWPerc);
- pausebounds = { //pause button, click/hover region
- x: size.pw,
- y: size.ph * 0.44,
- w: sidewidth,
- h: size.ph * 0.05
- };
- startbounds = {
- x: 0,
- y: (size.ph / 2) * 0.8,
- w: size.pw + sidewidth,
- h: (size.ph / 2) * 0.4
- };
- muteSFXbounds = {
- x: size.pw,
- y: size.ph * 0.55,
- w: sidewidth,
- h: size.ph * 0.04
- };
- muteMusicbounds = {
- x: size.pw,
- y: size.ph * 0.65,
- w: sidewidth,
- h: size.ph * 0.04
- };
- //render resource images
- //render scaling svg DOM: img_block can be used in ctx.drawImage at the end
- var svg_block = document.querySelector("svg.block");
- svg_block.setAttribute("width", size.bw);
- svg_block.setAttribute("height", size.bh);
- var xml = new XMLSerializer().serializeToString(svg_block);
- var img = 'data:image/svg+xml;base64,' + btoa(xml);
- img_block = document.querySelector("img.block");
- img_block.src = whitePx; //change of src to force rerender/override cache
- img_block.src = img;
- //render raster image, no rescaling
- img_back = document.querySelector("img.back");
- //gradient creation
- gradients=[];
- var grad = ctx.createLinearGradient(0, 0, 0, size.ph); //sidebar background
- grad.addColorStop(0, "rgba(255,255,255,0.1)");
- grad.addColorStop("0.5", "rgba(0,100,0,0.5)");
- grad.addColorStop(1, "rgba(255,255,255,0.1)");
- gradients.push(grad);
- grad = ctx.createLinearGradient(0, pausebounds.y, 0, pausebounds.y + pausebounds
- .h); //pause hover text color
- grad.addColorStop(0, "rgba(255,255,255,1)");
- grad.addColorStop("0.5", "rgba(0,100,0,1)");
- grad.addColorStop(1, "rgba(255,255,255,1)");
- gradients.push(grad);
- grad = ctx.createLinearGradient(0, 0, 0, size.ph); //splash screen background
- grad.addColorStop(0, "rgba(255,255,255,0.1)");
- grad.addColorStop("0.4", "rgba(0,100,0,1)");
- grad.addColorStop("0.6", "rgba(0,100,0,1)");
- grad.addColorStop(1, "rgba(255,255,255,0.1)");
- gradients.push(grad);
- grad = ctx.createLinearGradient(0, startbounds.y, 0, startbounds.y + startbounds
- .h); //START text color
- grad.addColorStop(0, "rgba(255,255,255,1)");
- grad.addColorStop("0.5", "rgba(0,100,0,1)");
- grad.addColorStop(1, "rgba(255,255,255,1)");
- gradients.push(grad);
- }
- function tileBackground(bgw, bgh) { //background is not rescaled, so we tile it
- for (var y = 0; y < Math.ceil(size.ph / bgh); ++y) {
- for (var x = 0; x < Math.ceil((size.pw+sidewidth) / bgw); ++x) {
- ctx.drawImage(img_back, x * bgw, y * bgh);
- }
- }
- }
- function getRandomInt(max) { //random integer between 0 and max
- return Math.floor(Math.random() * Math.floor(max));
- }
- function mInBounds(bounds) { //mouse coordinates within bounds (x,y,w,h)
- if (mx > bounds.x && mx < bounds.x + bounds.w && my > bounds.y && my < bounds.y + bounds.h)
- return true;
- return false;
- }
- function dropPixel(delay) {
- //move dropping pixels down.
- //dropspeed is 1 block /s using getSeconds!=lastsec
- //delay=false to drop multiple times without delay (e.g. drop to bottom)
- //returns 1 when form stuck and new form created
- var dat = new Date();
- if (!delay || lastsec != dat.getSeconds()) {
- for (var i = 0; i < pixels.length; ++i) pixels[i].y++;
- lastsec = dat.getSeconds();
- } else {
- return 0;
- }
- var dropped = false;
- for (var i = 0; i < pixels.length; ++i) { //check if stuck (bottom or overlaying other form)
- if (pixels[i].y < 0) continue;
- if (pixels[i].y == size.h + 1 || grid[pixels[i].y][pixels[i].x] == 1) dropped = true;
- }
- if (dropped) { //if stuck, new form
- newPixel(true);
- return 1;
- }
- return 0;
- }
- function newPixel(drop) { //create new form
- //curform=forms[...] is reference, not copy.
- //Object.assign also only shallow copy with deep references
- //solution is JSON-copy to test changes without applying
- //otherwise rotating would also rotate base-forms
- curForm = JSON.parse(JSON.stringify(forms[nextFormInd]));
- nextFormInd = getRandomInt(forms.length);
- for (var i = 0; i < pixels.length; ++i) {
- if (drop) { //current form overlays form on grid, so move it up again
- pixels[i].y--;
- grid[pixels[i].y][pixels[i].x] = 1; //store form on grid
- }
- pixels[i].y = 0 + curForm.y[i]; //new form generation
- pixels[i].x = Math.floor(size.w / 2.0) - 1 + curForm.x[i];
- if (grid[pixels[i].y][pixels[i].x] == 1)
- return endGame(); //newly created form blocked = game_over
- }
- }
- //delete lines, index in ys-array. also awards scores.
- function deleteFullLine(ys) {
- if (ending) return;
- var y;
- for (var yi = ys.length - 1; yi >= 0; --yi) {
- y = ys[yi];
- ny = new Array(size.w + 1);
- ny.fill(0);
- grid.splice(y, 1);
- grid.unshift(ny);
- }
- score += rewards[ys.length - 1];
- deleting = false;
- }
- //checks for full lines, marks grids for highlight (=2) for 1s and triggers deleteFullLine
- function clearFullLine() {
- var su = 0;
- var ny;
- var ys = [];
- for (var y = size.h; y >= 0; --y) {
- su = 0;
- for (var x = 0; x < size.w; ++x)
- su += grid[y][x];
- if (su == size.w) {
- ys.push(y);
- for (var x = 0; x < size.w; ++x)
- grid[y][x] = 2;
- }
- }
- if (ys.length > 0) {
- setTimeout(deleteFullLine.bind(null, ys), 1000);
- if (playSFX) audio_clean.play();
- deleting = true;
- }
- }
- //ending animation. recursive call to fill grid upwards line-per-line 50ms step.
- function fillUpwards(line,
- resolve
- ) { //called from a Promise, so "resolve" is returning the Promise and trigger its "then()" function
- for (var x = 0; x < size.w; ++x)
- grid[line][x] = 1;
- if (line > 0) setTimeout(fillUpwards.bind(null, line - 1, resolve), 50);
- else setTimeout(resolve, 1000);
- }
- function animFillUpwards() { //triggers fillUpward-animation and returns a promise so you can wait for its end.
- return new Promise(function (resolve, reject) {
- fillUpwards(size.h, resolve);
- });
- }
- function endGame() { //game ends. flag set, animFIllUpwards triggered. afterwards, starting-splashscreen flag set.
- ending = true;
- if (playSFX) audio_gameover.play();
- animFillUpwards()
- .then(function () {
- ending = false;
- starting = true;
- });
- }
- function renderGrid() { //render grid and pixels to the playboard
- //ctx.fillStyle = 'rgb(255,225,225)'; //plain color background
- //ctx.fillRect(0, 0, size.pw, size.ph);
- tileBackground(400, 400); //tiled background, width/height of image
- for (var cy = 0; cy < size.h + 1; ++
- cy) { //render set blocks (grid=1) or highlighted/deleting ones (grid=2)
- for (var cx = 0; cx < size.w + 1; ++cx) {
- if (grid[cy][cx] == 1) { //set blocks
- ctx.fillStyle = 'rgba(255,0,0,0.2)'; //reddish
- ctx.drawImage(img_block, cx * size.bw, cy * size
- .bh); //img_block from svg canvas is already scaled correctly
- ctx.fillRect(cx * size.bw, cy * size.bh, size.bw, size
- .bh); //change image by drawing transparent above
- } else if (grid[cy][cx] == 2) { //deleting blocks
- ctx.fillStyle = 'rgba(255,255,255,0.2)'; //whitish
- ctx.drawImage(img_block, cx * size.bw, cy * size.bh);
- ctx.fillRect(cx * size.bw, cy * size.bh, size.bw, size.bh);
- }
- }
- }
- ctx.fillStyle = 'rgba(0,0,0,0.2)'; //moving blocks, blackish
- for (var i = 0; i < pixels.length; ++i) {
- ctx.drawImage(img_block, pixels[i].x * size.bw, pixels[i].y * size.bh);
- ctx.fillRect(pixels[i].x * size.bw, pixels[i].y * size.bh, size.bw, size.bh);
- }
- if (paused) {
- ctx.textAlign = "center";
- ctx.textBaseline = "middle";
- ctx.font = (size.pw / 4) + "px Georgia";
- ctx.fillStyle = gradients[1];
- ctx.fillText("PAUSE", size.pw / 2, size.ph / 2);
- ctx.strokeStyle = "rgb(0,155,0)";
- ctx.strokeText("PAUSE", size.pw / 2, size.ph / 2);
- }
- }
- function renderSidebar() {
- ctx.fillStyle = gradients[0]; //background sidebar
- ctx.fillRect(size.pw, 0, sidewidth, size.ph);
- ctx.fillStyle = "rgba(255,255,255,0.5)"; //white highlight bg for numbers
- ctx.fillRect(size.pw, size.ph * 0.1, sidewidth, size.ph * 0.05); //score background
- ctx.fillRect(size.pw, size.ph * 0.25, sidewidth, size.ph * 0.15); //next preview background
- canvas.style.cursor = "default";
- //hover over pause button
- if (mInBounds(pausebounds)) {
- ctx.fillStyle = "rgba(150,255,150,0.8)";
- canvas.style.cursor = "pointer";
- } else { //default style
- ctx.fillStyle = "rgba(150,255,150,0.4)";
- }
- ctx.fillRect(pausebounds.x, pausebounds.y, pausebounds.w, pausebounds.h);
- for (var i = 0; i < curForm.x.length; ++i) { //render next
- ctx.drawImage(img_block,
- size.pw + Math.floor((3 - forms[nextFormInd].w / 2) * size.bw / 2) +
- forms[nextFormInd].x[i] * size.bw / 2,
- size.ph * 0.29 + forms[nextFormInd].y[i] * size.bh / 2 + (1 - forms[nextFormInd].h /
- 2) * size
- .bh / 2,
- size.bw / 2,
- size.bh / 2); //some math to make blocks 1/2 wide and center on field
- }
- //rendered text
- ctx.textAlign = "center";
- ctx.textBaseline = "top";
- ctx.font = size.ph * 0.04 +
- "px Georgia"; //font.size in px, but rescale() will also scale it with parent Element-height
- ctx.fillStyle = "black";
- ctx.fillText(score, size.pw + sidewidth / 2, size.ph * 0.1);
- ctx.fillText("SCORE", size.pw + sidewidth / 2, size.ph * 0.06);
- ctx.fillText("NEXT", size.pw + sidewidth / 2, size.ph * 0.20);
- ctx.fillText("PAUSE", size.pw + sidewidth / 2, size.ph * 0.45);
- //mutebutton
- if (playSFX)
- ctx.fillStyle = "green";
- else
- ctx.fillStyle = "red";
- ctx.fillRect(muteSFXbounds.x, muteSFXbounds.y, muteSFXbounds.w, muteSFXbounds.h);
- ctx.fillStyle = "black";
- ctx.fillText("SFX", size.pw + sidewidth / 2, muteSFXbounds.y);
- if (mInBounds(muteSFXbounds)) {
- canvas.style.cursor = "pointer";
- }
- //mutebutton
- if (playMusic)
- ctx.fillStyle = "green";
- else
- ctx.fillStyle = "red";
- ctx.fillRect(muteMusicbounds.x, muteMusicbounds.y, muteMusicbounds.w, muteMusicbounds.h);
- ctx.fillStyle = "black";
- ctx.fillText("MUSIC", size.pw + sidewidth / 2, muteMusicbounds.y);
- if (mInBounds(muteMusicbounds)) {
- canvas.style.cursor = "pointer";
- }
- }
- function renderSplash() { //start screen
- var dat = new Date(); //date for pulsing effect
- ctx.fillStyle = gradients[2]; //background
- ctx.fillRect(0, 0, size.pw + sidewidth, size.ph);
- //start text filled with gradient
- ctx.textAlign = "center";
- ctx.textBaseline = "middle";
- ctx.font = (size.pw / 4) + "px Georgia";
- ctx.fillStyle = gradients[3];
- ctx.fillText("START", (size.pw + sidewidth) / 2, size.ph / 2);
- //pulsing outline effect
- if (dat.getMilliseconds() < 500) //brighter first 1/2s, darker last 1/2s, 1s period
- ctx.strokeStyle = "rgb(0," + dat.getMilliseconds() / 500 * 255 +
- ",0)"; //linear transition of green-part
- else
- ctx.strokeStyle = "rgb(0," + (255 - (dat.getMilliseconds() - 500) / 500 * 255) + ",0)";
- ctx.strokeText("START", (size.pw + sidewidth) / 2, size.ph / 2);
- //hover Start text
- if (mInBounds(startbounds)) {
- canvas.style.cursor = "pointer";
- } else {
- canvas.style.cursor = "default";
- }
- }
- //main render cycle.
- //requestAnimationFrame renders as often as possible, but within screen rendering speed.
- //typically around 60fps.
- //modern browsers don't render when canvas not on screen/different tab.
- function draw() {
- if (!deleting && !ending && !paused && !starting) { //flags where normal game is paused
- dropPixel(true); //dropPixel has an inbuilt 1s delay per drop
- clearFullLine(); //check for full lines and remove with animation
- }
- renderGrid
- (); //renders set, moving and highlighted blocks. Input(Key/mouse) are immediatelly reacted to.
- renderSidebar(); //renders sidebar
- if (starting) renderSplash(); //start of game
- window.requestAnimationFrame(draw);
- }
- init(); //start game
- window.requestAnimationFrame(draw); //render game
- //user input section
- canvas.addEventListener("mouseup", function (evt) { //click
- if (mInBounds(pausebounds) && !ending && !starting && !deleting) { //pause button
- paused = !paused; //toggle pause flag
- } else
- if (mInBounds(startbounds) && starting) { //start button
- init(); //restart the game
- starting = false; //end starting screen
- } else
- if (mInBounds(muteSFXbounds)) { //mute sfx button
- playSFX = !playSFX;
- }
- if (mInBounds(muteMusicbounds)) { //mute music button
- playMusic = !playMusic;
- if (!playMusic) audio_background.pause();
- else audio_background.play();
- }
- });
- canvas.addEventListener("mousemove", function (evt) { //fetch mouse position
- var BB = canvas.getBoundingClientRect();
- mx = parseInt(evt.clientX - BB.left);
- my = parseInt(evt.clientY - BB.top);
- });
- window.addEventListener("resize", function () { //rescale on window-change
- rescale();
- draw();
- });
- window.addEventListener("keydown", function (e) { //prevent keyboard scrolling events on page
- // space and arrow keys
- if ([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
- e.preventDefault();
- }
- }, false);
- window.addEventListener("keyup", function (keyEv) { //key input
- var allow = true;
- var newX, newY;
- if ((starting && keyEv.which != 32) || deleting || ending || (paused && keyEv.which != 80))
- return;
- //disable input when splash, while animation (deleting/ending) and if paused, unless it's p to end pause
- switch (keyEv.which) { //fetch pressed key
- case 80: //p
- paused = !paused;
- break;
- case 32: //space
- if (starting) {
- init();
- starting = false;
- } else {
- if (playSFX) audio_down.load();
- if (playSFX) audio_down.play();
- while (dropPixel(false) == 0) {}; //drop to bottom
- }
- break;
- case 38: //up turn
- //turn moving blocks by 90deg left
- if (playSFX) audio_shuffle.load();
- if (playSFX) audio_shuffle.play();
- zwiForm = JSON.parse(JSON.stringify(curForm)); //new rotated blocks in zwiForm
- for (var i = 0; i < pixels.length; ++i) {
- zwiForm.x[i] = turn[0][0] * curForm.x[i] + turn[1][0] * curForm.y[i];
- zwiForm.y[i] = turn[0][1] * curForm.x[i] + turn[1][1] * curForm.y[i];
- }
- //check of rotated form actually fits
- for (var i = 0; i < pixels.length; ++i) {
- newX = pixels[i].x - curForm.x[i] + zwiForm.x[i];
- newY = pixels[i].y - curForm.y[i] + zwiForm.y[i];
- if (newX < 0 || newX > size.w - 1) allow = false;
- else if (newY < 0 || newY > size.h - 1) allow = false;
- else if (grid[newY][newX] == 1) allow = false;
- }
- if (allow) { //new form fits, override current form with rotated form
- for (var i = 0; i < pixels.length; ++i) { //remove current form
- pixels[i].x -= curForm.x[i];
- pixels[i].y -= curForm.y[i];
- }
- curForm = JSON.parse(JSON.stringify(
- zwiForm)); //copy rotated form to current
- for (var i = 0; i < pixels.length; ++i) { //apply rotated form
- pixels[i].x += curForm.x[i];
- pixels[i].y += curForm.y[i];
- }
- }
- break;
- case 40: //down move
- for (var i = 0; i < pixels.length; ++i) //all moving pixels
- if (!(pixels[i].y < size.h - 1 && grid[pixels[i].y + 1][pixels[i].x] !=
- 1)) //check for grid-boundaries and existing blocks
- allow = false;
- if (allow) //only move when allowed
- for (var i = 0; i < pixels.length; ++i) pixels[i].y++;
- break;
- case 37: //left move
- for (var i = 0; i < pixels.length; ++i)
- if (!(pixels[i].x > 0 && grid[pixels[i].y][pixels[i].x - 1] != 1))
- allow = false;
- if (allow)
- for (var i = 0; i < pixels.length; ++i) pixels[i].x--;
- break;
- case 39: //right move
- for (var i = 0; i < pixels.length; ++i)
- if (!(pixels[i].x < size.w - 1 && grid[pixels[i].y][pixels[i].x + 1] !=
- 1))
- allow =
- false;
- if (allow)
- for (var i = 0; i < pixels.length; ++i) pixels[i].x++;
- break;
- };
- });
- })();
- </script>
- </body>
- </html>
Add Comment
Please, Sign In to add comment