Block Blast
by AtomicBolt46471 lines8.8 KB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Block Blast</title>
<style>
* { box-sizing:border-box; }
body {
margin:0;
background:linear-gradient(135deg,#10152d,#222d52);
color:white;
font-family:Arial,sans-serif;
text-align:center;
min-height:100vh;
}
h1 {
color:#70eaff;
font-size:38px;
margin:20px 0 5px;
text-shadow:0 0 15px #27aaff;
}
.subtitle { color:#aab9dd; }
.stats {
display:flex;
justify-content:center;
gap:35px;
margin:20px;
}
.stat {
background:#26365e;
padding:12px 25px;
border-radius:12px;
min-width:115px;
}
.stat small {
color:#aab9dd;
display:block;
}
.stat strong {
font-size:27px;
color:#ffe66d;
}
#board {
display:grid;
grid-template-columns:repeat(8,1fr);
gap:5px;
width:min(92vw,440px);
aspect-ratio:1;
margin:15px auto;
padding:8px;
background:#101a35;
border-radius:12px;
box-shadow:0 0 25px #0008;
}
.cell {
background:#26365b;
border-radius:5px;
border:1px solid #35466c;
}
.cell.filled {
background:var(--color);
border:2px solid #ffffff55;
box-shadow:inset 0 -4px 0 #0002;
}
#pieces {
display:flex;
justify-content:center;
align-items:center;
gap:15px;
margin:20px auto;
max-width:450px;
}
.piece {
width:30%;
height:115px;
background:#26365e;
border:3px solid transparent;
border-radius:12px;
display:flex;
justify-content:center;
align-items:center;
cursor:pointer;
}
.piece.selected {
border-color:#ffe66d;
background:#394d7c;
}
.piece.used { opacity:0.18; }
.mini {
display:grid;
gap:3px;
}
.mini-cell {
width:21px;
height:21px;
border-radius:3px;
background:var(--color);
border:1px solid #ffffff55;
}
button {
padding:12px 25px;
border:0;
border-radius:10px;
background:#55d6ff;
font-size:17px;
font-weight:bold;
cursor:pointer;
margin:8px;
}
button:hover { background:#a3ecff; }
#message {
min-height:25px;
color:#ffe66d;
font-weight:bold;
}
#gameover {
display:none;
position:fixed;
inset:0;
background:#080d20ed;
z-index:5;
align-items:center;
justify-content:center;
flex-direction:column;
}
#gameover h2 {
font-size:45px;
color:#ff6969;
}
.instructions {
color:#aab9dd;
font-size:14px;
margin-bottom:25px;
}
</style>
</head>
<body>
<h1>🟦 BLOCK BLAST</h1>
<p class="subtitle">Place blocks. Clear lines. Beat your high score!</p>
<div class="stats">
<div class="stat">
<small>SCORE</small>
<strong id="score">0</strong>
</div>
<div class="stat">
<small>BEST</small>
<strong id="best">0</strong>
</div>
</div>
<div id="board"></div>
<p id="message">Select a block to start!</p>
<div id="pieces"></div>
<p class="instructions">
Select a block, then click an empty space on the board.
<br>Complete rows or columns to clear them!
</p>
<button onclick="restart()">🔄 NEW GAME</button>
<div id="gameover">
<h2>GAME OVER!</h2>
<h3>Your score: <span id="finalscore">0</span></h3>
<button onclick="restart()">PLAY AGAIN</button>
</div>
<script>
const SIZE = 8;
const colors = [
"#38bdf8",
"#f472b6",
"#a78bfa",
"#facc15",
"#4ade80",
"#fb923c",
"#f87171"
];
const shapes = [
[[0,0]],
[[0,0],[0,1]],
[[0,0],[0,1],[0,2]],
[[0,0],[1,0],[2,0]],
[[0,0],[0,1],[1,0],[1,1]],
[[0,0],[0,1],[0,2],[0,3]],
[[0,0],[1,0],[2,0],[3,0]],
[[0,0],[0,1],[0,2],[0,3],[0,4]],
[[0,0],[1,0],[2,0],[3,0],[4,0]],
[[0,0],[1,0],[1,1]],
[[0,0],[0,1],[1,1]],
[[0,0],[1,0],[2,0],[2,1]],
[[0,0],[1,0],[2,0],[2,-1]],
[[0,0],[0,1],[0,2],[1,2]],
[[0,0],[1,0],[1,1],[2,1]],
[[0,0],[0,1],[1,1],[1,2]],
[[0,0],[1,0],[2,0],[1,1]],
[[0,0],[1,0],[2,0],[1,-1],[1,1]],
[[0,0],[1,0],[2,0],[0,1],[1,1],[2,1]]
];
let grid;
let pieces;
let selected = -1;
let score = 0;
let best = 0;
let gameEnded = false;
const board = document.getElementById("board");
const piecesBox = document.getElementById("pieces");
function makeBoard() {
board.innerHTML = "";
for(let r=0;r<SIZE;r++) {
for(let c=0;c<SIZE;c++) {
const cell = document.createElement("div");
cell.className = "cell";
cell.dataset.r = r;
cell.dataset.c = c;
cell.onclick = () => placeBlock(r,c);
board.appendChild(cell);
}
}
}
function randomPiece() {
const shape = shapes[Math.floor(Math.random()*shapes.length)];
return {
shape: shape.map(p=>[...p]),
color: colors[Math.floor(Math.random()*colors.length)]
};
}
function newPieces() {
pieces = [randomPiece(),randomPiece(),randomPiece()];
selected = -1;
renderPieces();
}
function renderBoard() {
[...board.children].forEach(cell=>{
const r = Number(cell.dataset.r);
const c = Number(cell.dataset.c);
cell.classList.toggle("filled",grid[r][c] !== null);
if(grid[r][c]) {
cell.style.setProperty("--color",grid[r][c]);
} else {
cell.style.removeProperty("--color");
}
});
}
function renderPieces() {
piecesBox.innerHTML = "";
pieces.forEach((piece,index)=>{
const button = document.createElement("div");
button.className = "piece";
if(index===selected) button.classList.add("selected");
if(!piece) button.classList.add("used");
if(piece) {
const mini = document.createElement("div");
mini.className = "mini";
const minR = Math.min(...piece.shape.map(p=>p[0]));
const maxR = Math.max(...piece.shape.map(p=>p[0]));
const minC = Math.min(...piece.shape.map(p=>p[1]));
const maxC = Math.max(...piece.shape.map(p=>p[1]));
mini.style.gridTemplateColumns =
`repeat(${maxC-minC+1},21px)`;
for(let r=minR;r<=maxR;r++) {
for(let c=minC;c<=maxC;c++) {
const block = document.createElement("div");
if(piece.shape.some(p=>p[0]===r && p[1]===c)) {
block.className = "mini-cell";
block.style.setProperty("--color",piece.color);
} else {
block.style.width="21px";
block.style.height="21px";
}
mini.appendChild(block);
}
}
button.appendChild(mini);
button.onclick = () => {
if(gameEnded) return;
selected=index;
renderPieces();
document.getElementById("message").textContent =
"Now choose a place for your block!";
};
}
piecesBox.appendChild(button);
});
}
function canPlace(piece,r,c) {
return piece.shape.every(([dr,dc])=>{
const y=r+dr;
const x=c+dc;
return y>=0 && y<SIZE &&
x>=0 && x<SIZE &&
grid[y][x]===null;
});
}
function placeBlock(r,c) {
if(gameEnded) return;
if(selected===-1 || !pieces[selected]) {
document.getElementById("message").textContent =
"Select a block first!";
return;
}
const piece=pieces[selected];
if(!canPlace(piece,r,c)) {
document.getElementById("message").textContent =
"That block doesn't fit there!";
return;
}
piece.shape.forEach(([dr,dc])=>{
grid[r+dr][c+dc]=piece.color;
});
score+=piece.shape.length*10;
pieces[selected]=null;
selected=-1;
const cleared=clearLines();
if(cleared>0) {
score+=cleared*100;
document.getElementById("message").textContent =
"💥 AMAZING! "+cleared+" lines cleared!";
} else {
document.getElementById("message").textContent =
"Nice move!";
}
updateStats();
renderBoard();
renderPieces();
if(pieces.every(p=>p===null)) {
newPieces();
}
checkGameOver();
}
function clearLines() {
const rows=[];
const cols=[];
for(let r=0;r<SIZE;r++) {
if(grid[r].every(cell=>cell!==null)) rows.push(r);
}
for(let c=0;c<SIZE;c++) {
if(grid.every(row=>row[c]!==null)) cols.push(c);
}
rows.forEach(r=>{
for(let c=0;c<SIZE;c++) grid[r][c]=null;
});
cols.forEach(c=>{
for(let r=0;r<SIZE;r++) grid[r][c]=null;
});
return rows.length+cols.length;
}
function checkGameOver() {
const available=pieces.filter(p=>p!==null);
if(available.length===0) return;
const possible=available.some(piece=>{
for(let r=0;r<SIZE;r++) {
for(let c=0;c<SIZE;c++) {
if(canPlace(piece,r,c)) return true;
}
}
return false;
});
if(!possible) {
gameEnded=true;
document.getElementById("finalscore").textContent=score;
document.getElementById("gameover").style.display="flex";
}
}
function updateStats() {
best=Math.max(best,score);
document.getElementById("score").textContent=score;
document.getElementById("best").textContent=best;
}
function restart() {
grid=Array.from({length:SIZE},()=>Array(SIZE).fill(null));
score=0;
selected=-1;
gameEnded=false;
document.getElementById("gameover").style.display="none";
document.getElementById("message").textContent=
"Select a block to start!";
updateStats();
makeBoard();
newPieces();
renderBoard();
}
restart();
</script>
</body>
</html>Game Source: Block Blast
Creator: AtomicBolt46
Libraries: none
Complexity: complex (471 lines, 8.8 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: block-blast-atomicbolt46" to link back to the original. Then publish at arcadelab.ai/publish.