Flappy Lego
How do I make an flappy lego?
I got the idea from : https://github.com/JuanPotato/Legofy For some reason the collision detection has broken (has to do with global composite operation). Still, something funny to end the week with :). What is a flappy lego? How do you make a flappy lego? This script and codes were developed by Sakri Rosenstrom on 13 September 2022, Tuesday.
Flappy Lego - Script Codes HTML Codes
<!DOCTYPE html>
<html >
<head> <meta charset="UTF-8"> <title>Flappy Lego</title> <link rel="stylesheet" href="css/style.css">
</head>
<body> <script src="js/index.js"></script>
</body>
</html>
Flappy Lego - Script Codes CSS Codes
html, body{ margin : 0px; width : 100%; height : 100%; overflow: hidden; }
Flappy Lego - Script Codes JS Codes
//inspired by https://github.com/JuanPotato/Legofy
//context / more comments at the top of the JS here : https://codepen.io/sakri/pen/NGzvEo
//For some reason the collision detection has broken, has to do with globalcomposite operation (works in FF not in chrome). Also, for some reason the globalCompositeOperation = "overlay" works in my Lego Text Pen, but not in this one?! so Had to go for the lame alpha trick.
//sprite sheet : http://sakri.net/stuff/canvas/FlappyBird32x32Tall.png
var readyStateCheckInterval = setInterval( function() { if (document.readyState === "complete") { clearInterval(readyStateCheckInterval); initGame(); }
}, 10);
var bgLoc = {x:0, y:0, width:32, height:32};
var groundLoc = {x:0, y:31, width:35, height:1};
var instructionsLoc = {x:6, y:49, width:17, height:21};
var gameOverLoc = {x:6, y:32, width:21, height:17};
var birdLocs = [{x:32, y:0, width:5, height:3}, {x:32, y:3, width:5, height:3}, {x:32, y:6, width:5, height:3}];
var tubeLoc = {x:0, y:32, width:6, height:44};
var hiscoreLoc = {x:6, y:70, width:30, height:10};
var scoreLocs = [32, 9, 27, 32, 32, 32, 27, 41, 32, 41, 27, 50, 32, 50, 27, 59, 32, 59, 32, 18];
var legoBrickSource = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAHS0lEQVRIiX2XaU8TXxuH/Ubmr4iJkc1E3CWicQEVEKHQoXToTNth9uXM2taiEdGgaFx4Ydyixq93PS/MHKmS58WdTDptr3v9nfscqdfrWJZFu93+x1qt1oA1m01pmqahaRq6rktrNpvye4f9Ttd1DMNAURSOBEFAv98nz3OyLJOW5/mAlZ+V79M0JU3TgeeDliQJSZIQx/GAFUXB5uYmR2zbJs9zhBDEcUwURURR9M8P4jhGCIHv+3ieh+M4OI6D67p4nkcYhgghEEIQRRFhGBKGIUEQSPN9nziOabfbv8GdTucfSOlxkiQSKITg0aNH7Ozs8PLlS169esXz58/p9XpEUSQdKJ0snYiiiCAICMOQNE3/gLvdLkmSyBSVKUySRAJ3d3f58uULP3784Nu3b3z9+pVv377x48cPfv36xefPn9ne3iaKIhnZwQyWWRgAdzodCTxYoyAI2Nra4tOnT3z58oW9vT36/f5AXYui4NmzZ+zv7/Pz50/29/cpioIgCIiiaCDqQ8F/N0sQBGxvb/P9+3devXpFFEU4joPv+/IPhRCEYYjneXieR6/X4+PHj3z69ImiKGS2Dtb9/4KFEHS7Xfb393n8+DG2bcuG+/uPDtbPcRzCMOTt27e8e/eOOI5lzcuo0zTFMIxBcFlXIQQvXryg3+/jui5CCDkaYRjiuq7s6iAIsG0bx3EQQsh3b9++ZWdnB9d1pcNRFJFl2Z+Ie70eaZqS5zm+75NlGVtbWwghSNNUelyOSFEUdDodwjDEtm2EEDLdnufh+z5JkrC3t4fv+ziOQ5IkEiwj7vV6ZFlGHMc4jkOe5xRFIeu2vb2N4zgYhkGaprx+/ZrXr1+TZRmu6/Lu3TvevHmDYRgIIXj//j1Pnjzh0aNHxHGMpmky6izL/ghICXYchzL1eZ5jmiau65LnOUEQoOs6juOg6zpra2s0m02iKKJSqcgudhwHRVHodDp0u13SNGVjY0NmJs/z3xFblkW320UIQavVwrIsCTYMA9u2ZfMYhoFpmui6jmVZMsLl5WWWlpZot9v4vo+iKJimiRCCoiio1+tomkYYhn9SbVkWRVEQhiGqqrK5uSmVzDTNgWZqt9vs7OzQ6/VotVqUcptlGbZts7m5SRiGtNttKZFFUVCr1ajVanieR5Ikv5vLsizSNMXzPBRFod1u0+v18H0fy7IQQkioaZo8f/6cfr/PxsYGruvi+z67u7ukaYpt27iui2macgLSNGV1dZVKpSLH0jAMjmxubpIkCZZlsby8TKPRoNvtYlmWlD7f9zEMgyiKZNpKh9fX12UvRFGEruvyubTFxcUBcLvd/g2O4xjLsnj48CGKokiw4ziYpolt25imKSMvI4vjGFVVCcNQqpSqqsRxjOu6JEmC67rcvXsXRVHkrEtwkiQ4jsPq6irz8/MIITBNk36/z4cPH3j69CmapvHs2TM+fPjAkydPqFarvHjxgjdv3mBZFisrK+zt7bG7u4vruti2TZZlNBoNbty4Qa1Wk2DZXGWNVVXlxo0bNJtNPM/DMAw5EoqioOs6SZKQ5zm1Wo319XU8z6PVarGyskKj0cDzPBqNhhSf+/fvc+3aNVRVHUy1ZVkkSYLneWiaxs2bN5mdnSXPczRNY3FxkWazieM4VCoVFhcXabVaxHFMrVajUqnImiqKgqIoUqGazSZXr15lZmaGRqOB4zh/wKZpSrCu6ywuLnL58mUURaHf78slIAgCecYGQSBhZfcefF/q/e3bt7lw4QJLS0vS+UPBhmFQrVa5fv06k5OT6LouZbFccf7W5FJcyvUmiiI6nQ7VapWxsTGmp6dZXV2l3W4fDi7FXFVV5ufnOXfuHJOTk9RqNXm0/b1DHYSGYUiSJPR6PdbW1hgdHeXs2bPMzc1Rr9flVAyA0zSVS5xhGKysrHDr1i3Gx8cZGRnh/v37uK5LURTkef7PBlk2XKfTYWlpiaGhIUZGRrh16xaVSkWqXHnEHgp2HAdN03jw4AHT09OMjo5y8uRJJicnmZ+fR9M0eQ77vo/rujSbTR4+fMjFixf577//OH36NNPT0zx48IBGo4FlWQNn9qHgUio3NjaYm5vjypUrjI+PMzQ0xPDwMGNjY5w/f56pqSmuXLnCuXPnGBsb49ixYxw9epTR0VGmpqaYm5tDVVUpQIdGnGWZjOBv+MLCAlNTU5w5c4ZTp05x8uRJhoeHOXHiBENDQxw/fpwTJ05w6tQpJiYmmJqaYmFhQUIPRut53qByZVkmZa8Ee56HZVnouk6lUuH27dtcvHiRiYkJRkdHGRkZ4fTp04yMjDA+Ps6lS5e4c+cOKysr6Lr+T6TlVEhweYUpG6dcdcrmKdcawzBYX19naWmJe/fuMTs7y8zMDPfu3WN5eRlVVTEMQy715QFxcF9LkoRut4vruhxRVVWK/98XtoOXtGazSaPRoF6vs7a2RrVapVqtoigK9XqdjY0NNE2j0WjIy9zBy1r5mWEYrK2t8T9Fl5UzxezQ/AAAAABJRU5ErkJggg==";
var flappyBirdSource = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACUAAABQCAYAAACecbxxAAACY0lEQVRoge2XPW4CMRCF5yooLeegpIw4SZp0dBF34DBIKSMOkKQJUgpyBuQUyYIZv/mx1wsGraXR4vXu+Jv3Zheg59e3cM3YbqbH+Dl8BiIiujYUEVEHtZvPwm4+C01AERF9LB+On5uAas6+uKdG+27Oviafvu1mGlq0L40WoOLRFFR8HKFGqLuFau7pa/I91SRUk/aJjb4/vB+D3xivea/xrkMotOElA9r38r0K14y4wVuC6sYI5YY6RkNQpzFC3TTU02Ya1vtF+AqrcMnP6/0iWUvAuoXH5QQ/EXZY16N16R4din8FoHmcULqO50Pnzs5bUNKmfBMNNlaFQ8HzfaG0Y7Q5ylkOhRTwHNnmIlSxfaVHL1SsWBEUUo5bADdKbZKvrWEfggIWovNZ9qH3x6VChvKoxNclJapCeY5oc+2zBO2ybwgobb0alKTCVaHQRpaCWjHZUJYtsGKhmVX1HpeTwKH+wUwr+LoEZdhHyXUaVIVIlIJWpfDqKAXJyYfW9CTIIm1eqUg7Ceopo4/cRRYUdkpUE4qYMuDcnUD16amL2uesEqqTqfZ5IiOycvWFou6GHraJeXrkqlZdTdX/Et4tlMs+5QvZhCrpKV6UWOCA/2ZUxYqg0BPHq+XrTvVs1a1fnkhyVGFGn/VTqkkodPMQUFXti5PB5AKUES6oM+UcCuW8JvBwvBI81dWByYBCm+ZA5heU+w85Xtd6SpubfdgHKq5SmqOeM/uwApQ6d0KdjwGUKoHyK8X955ta6/yI7onniWJsmEoZVoj3I8USpQaAUmEGhbKsQHMElWWfEtZ6n6BfqpBLl8a8BXQAAAAASUVORK5CYII=";
var spriteSheetImage = new Image();
spriteSheetImage.src = flappyBirdSource;
var legoBrick = new Image();
legoBrick.src = legoBrickSource;
var legoBG = new Image();
var spriteSheetCanvas = document.createElement("canvas");
spriteSheetCanvas.width = spriteSheetImage.width;
spriteSheetCanvas.height = spriteSheetImage.height;
var spriteSheetContext = spriteSheetCanvas.getContext("2d");
spriteSheetContext.drawImage(spriteSheetImage, 0, 0);
var renderCanvas = document.createElement("canvas");
renderCanvas.width = renderCanvas.height = 32;
var renderContext = renderCanvas.getContext("2d");
renderContext.globalCompositeOperation = "destination-over";
var collisionCanvas = document.createElement("canvas");
function drawSpriteSheetImage(context, locRect, x, y){ context.drawImage(spriteSheetImage, locRect.x, locRect.y, locRect.width, locRect.height, x, y, locRect.width, locRect.height);
}
var canvas, context, gameState, score, groundX = 0, birdY, birdYSpeed, birdX = 5, birdFrame = 0, activeTube, tubes = [], collisionContext, scale, scoreLoc = {width:5, height:9}, hiScore = 0;
var HOME = 0, GAME = 1, GAME_OVER = 2, HI_SCORE = 3;
function createLegoBG(){ var legoCanvas = document.createElement('canvas'); legoCanvas.width = canvas.width; legoCanvas.height = canvas.height; var legoContext = legoCanvas.getContext("2d"); for(var i=0; i<32; i++){ for(var j=0; j<32; j++){ legoContext.drawImage(legoBrick, 0, 0, 30, 30, j*30, i*30, 30, 30); } } legoBG.src = legoCanvas.toDataURL();
}
function initGame(){ canvas = document.createElement('canvas');//document.getElementById("gameCanvas"); canvas.style.position = "absolute"; document.body.appendChild(canvas); context = canvas.getContext("2d"); //context.globalCompositeOperation = "overlay"; scale = 30;//Math.floor(Math.min(window.innerHeight, window.innerWidth) / 32); canvas.width = scale * 32; canvas.height = scale * 32; canvas.style.left = window.innerWidth / 2 - (scale * 32) / 2 + "px"; canvas.style.top = window.innerHeight / 2 - (scale * 32) / 2 + "px"; createLegoBG(); window.addEventListener( "keydown", handleUserInteraction, false ); canvas.addEventListener('touchstart', handleUserInteraction, false); canvas.addEventListener('mousedown', handleUserInteraction, false); collisionCanvas.width = birdX + 8; collisionCanvas.height = 32; collisionContext = collisionCanvas.getContext("2d"); collisionContext.globalCompositeOperation = "xor"; startGame(); setInterval(loop, 40);
}
function startGame(){ gameState = HOME; birdYSpeed = score = 0; birdY = 14; for(var i = 0; i < 2; i++){ tubes[i] = {x : Math.round(48 + i * 19) }; setTubeY(tubes[i]); }
}
function loop(){ switch(gameState){ case HOME: renderHome(); break; case GAME : renderGame(); break; case GAME_OVER: renderGameOver(); break; case HI_SCORE : renderHiScore(); break; }
}
function handleUserInteraction(event){ switch(gameState){ case HOME: gameState = GAME; break; case GAME : birdYSpeed = -1.4;//"tap boost" break; case HI_SCORE: startGame(); break; } if(event){ event.preventDefault();//stop propagation chain }
}
function renderHome(){ renderContext.clearRect(0,0,32,32); drawSpriteSheetImage(renderContext, instructionsLoc, 32 - instructionsLoc.width - 1, 1); updateBirdHome(); renderGround(true); drawSpriteSheetImage(renderContext, bgLoc, 0, 0); renderToScale();
}
function renderGame(){ renderContext.clearRect(0,0,32,32); collisionContext.clearRect(0,0,collisionCanvas.width, collisionCanvas.height); renderScore(score, renderScoreXGame, 1); renderGround(true); renderTubes(); updateBirdGame(); checkCollision(); drawSpriteSheetImage(renderContext, bgLoc, 0, 0); renderToScale();
}
function renderGameOver(){ renderContext.clearRect(0, 0, 32, 32); drawSpriteSheetImage(renderContext, gameOverLoc, 5, 7 - birdFrame); renderGround(); drawSpriteSheetImage(renderContext, bgLoc, 0, 0); renderToScale(); if(++score % 8 == 0){ birdFrame++;//this is a quick hack to move the game over logo birdFrame %= 2; }
}
function renderHiScore(){ renderContext.clearRect(0, 0, 32, 32); drawSpriteSheetImage(renderContext, hiscoreLoc, 1, 5); renderScore(hiScore, renderScoreXHiScore, 16); renderGround(); drawSpriteSheetImage(renderContext, bgLoc, 0, 0); renderToScale();
}
function rgbToHex(r, g, b) { return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
function renderToScale(){ var i, data = renderContext.getImageData(0,0,32, 32).data; context.globalAlpha = 1; context.clearRect(0,0,canvas.width, canvas.height); for(i=0; i<data.length; i+=4){ context.fillStyle = "rgb("+data[i]+","+data[i+1]+","+data[i+2]+")"; //context.fillStyle = rgbToHex(data[i], data[i+1], data[i+2]); context.fillRect(((i/4) % 32) * scale, Math.floor(i / 128) * scale, scale, scale); } context.globalAlpha = .7; context.drawImage(legoBG, 0, 0);
}
function checkCollision(){ if(birdX == tubes[activeTube].x + 6){ score++; } if(score>20){ gameState = GAME_OVER; if(score > hiScore){ hiScore = score + 0; } setTimeout(function(){gameState = HI_SCORE}, 2500); } return; var collisionData = collisionContext.getImageData(birdX, birdY, 5, 3).data; var data = renderContext.getImageData(birdX, birdY, 5, 3).data; for(var i = 0; i< collisionData.length; i+=4){ if(collisionData[i+3] != data[i+3]){ return; console.log("SHIT FUCK!", i, birdX, birdY); gameState = GAME_OVER; if(score > hiScore){ hiScore = score + 0; } setTimeout(function(){gameState = HI_SCORE}, 2500); break; } }
}
function renderScore(score, xFunction, y){ var parts = score.toString().split(""); var i, index, length = parts.length; for(var i=0; i<length; i++){ index = parseInt(parts.pop())*2; scoreLoc.x = scoreLocs[index]; scoreLoc.y = scoreLocs[index + 1]; //drawSpriteSheetImage(renderContext, scoreLoc, 25 - 5 * i, 1); drawSpriteSheetImage(renderContext, scoreLoc, xFunction(i, length), y); }
}
function renderScoreXGame(index, total){ return 25 - 5 * index;
}
function renderScoreXHiScore(index, total){ return 12 + Math.floor((total/2)*5) - 5 * index;
}
function renderGround(move){ if(move && --groundX < bgLoc.width - groundLoc.width){ groundX = 0; } drawSpriteSheetImage(renderContext, groundLoc, groundX, 31);
}
function updateBirdHome(){ drawSpriteSheetImage(renderContext, birdLocs[birdFrame], birdX, birdY); birdFrame++; birdFrame %= 3;
}
function updateBirdGame(){ birdY = Math.round(birdY + birdYSpeed); birdYSpeed += .25;//Gravity, change this to your likings if(birdY < 0){ birdY = 0; birdYSpeed = 0; } if(birdY + 3 > bgLoc.height){ birdY = 28; birdYSpeed = 0; } renderContext.save(); collisionContext.save(); renderContext.translate(birdX, birdY); collisionContext.translate(birdX, birdY); drawSpriteSheetImage(renderContext, birdLocs[birdFrame], 0, 0); drawSpriteSheetImage(collisionContext, birdLocs[birdFrame], 0, 0); renderContext.restore(); collisionContext.restore(); birdFrame++; birdFrame %= 3;
}
function renderTubes(){ var i, tube; activeTube = tubes[0].x < tubes[1].x ? 0 : 1; for(i= 0; i < 2;i++){ tube = tubes[i]; if(--tube.x <= -6 ){ tube.x = 32; setTubeY(tube); } drawSpriteSheetImage(renderContext, tubeLoc, tube.x, tube.y ); drawSpriteSheetImage(collisionContext, tubeLoc, tube.x, tube.y ); }
}
function setTubeY(tube){ tube.y = Math.floor(Math.random() * (bgLoc.height - tubeLoc.height) );
}
Developer | Sakri Rosenstrom |
Username | sakri |
Uploaded | September 13, 2022 |
Rating | 3 |
Size | 7,262 Kb |
Views | 26,312 |
Find the perfect freelance services for your business! Fiverr's mission is to change how the world works together. Fiverr connects businesses with freelancers offering digital services in 500+ categories. Find Developer!
Name | Size |
Canvas Vasarely | 3,290 Kb |
Text On Fire | 7,247 Kb |
Flood Erase | 4,602 Kb |
Circular Logic Works Because... | 3,427 Kb |
Isometric Text | 8,538 Kb |
Classic text effect | 11,186 Kb |
Flappy Text | 8,763 Kb |
He-Man effect | 8,574 Kb |
Circular Wander Text | 9,998 Kb |
Ghost Text | 10,419 Kb |
Jasper is the AI Content Generator that helps you and your team break through creative blocks to create amazing, original content 10X faster. Discover all the ways the Jasper AI Content Platform can help streamline your creative workflows. Start For Free!
Name | Username | Size |
Midterm dry run | Jds317 | 1,649 Kb |
Calculator | Rzencoder | 4,572 Kb |
Touch Carousel - last, no gaps. | Berkin | 4,332 Kb |
Cloud upload | Jaflo | 2,774 Kb |
NeeilTimer | Neeilan | 2,836 Kb |
Playing with FlexBox | _Billy_Brown | 3,162 Kb |
A Pen by Jay | Jaycode | 3,784 Kb |
Pure CSS Animated Photo Stack | Depthdev | 2,486 Kb |
LDE old privacy page | Jasonangle | 2,339 Kb |
Parallax-ish Sliding Content | Jdsteinbach | 2,748 Kb |
Surf anonymously, prevent hackers from acquiring your IP address, send anonymous email, and encrypt your Internet connection. High speed, ultra secure, and easy to use. Instant setup. Hide Your IP Now!