'use strict'; /* Tekenen van een blokje met simpele 3D-schaduwen */ function drawCell(ctx, px, py, size, color) { ctx.fillStyle = color; ctx.fillRect(px, py, size, size); ctx.fillStyle = 'rgba(255,255,255,0.22)'; ctx.fillRect(px, py, size, size * 0.28); ctx.fillRect(px, py, size * 0.28, size); ctx.fillStyle = 'rgba(0,0,0,0.25)'; ctx.fillRect(px, py + size * 0.72, size, size * 0.28); ctx.fillRect(px + size * 0.72, py, size * 0.28, size); } /* Ghost piece: alleen een omlijning, half transparant */ function drawGhostCell(ctx, px, py, size, color) { ctx.save(); ctx.globalAlpha = 0.45; ctx.strokeStyle = color; ctx.lineWidth = Math.max(2, size * 0.12); ctx.strokeRect(px + 3, py + 3, size - 6, size - 6); ctx.restore(); } /* Het hoofd-bord */ function drawBoard(canvas, game) { const ctx = canvas.getContext('2d'); const size = CONSTANTS.CELL; const W = CONSTANTS.COLS * size; const H = CONSTANTS.ROWS * size; ctx.clearRect(0, 0, W, H); // achtergrond met subtiel verloop const grad = ctx.createLinearGradient(0, 0, 0, H); grad.addColorStop(0, '#121722'); grad.addColorStop(1, '#070a11'); ctx.fillStyle = grad; ctx.fillRect(0, 0, W, H); // gridlijnen ctx.strokeStyle = 'rgba(255,255,255,0.05)'; ctx.lineWidth = 1; for (let c = 1; c < CONSTANTS.COLS; c++) { ctx.beginPath(); ctx.moveTo(c * size, 0); ctx.lineTo(c * size, H); ctx.stroke(); } for (let r = 1; r < CONSTANTS.ROWS; r++) { ctx.beginPath(); ctx.moveTo(0, r * size); ctx.lineTo(W, r * size); ctx.stroke(); } // vastgezette blokken for (let r = 0; r < CONSTANTS.ROWS; r++) { for (let c = 0; c < CONSTANTS.COLS; c++) { const color = game.board[r][c]; if (color) drawCell(ctx, c * size, r * size, size, color); } } // flitsende rijen tijdens het wissen if (game.flashLines.length) { ctx.fillStyle = 'rgba(255,255,255,0.75)'; for (const r of game.flashLines) { ctx.fillRect(0, r * size, W, size); } } // ghost + actief blok if (game.piece && !game.over) { if (!game.locking) { const ghostY = game.ghostY(); if (ghostY !== game.piece.y) { const m = game.piece.matrix; for (let r = 0; r < m.length; r++) { for (let c = 0; c < m[r].length; c++) { if (!m[r][c]) continue; drawGhostCell(ctx, (game.piece.x + c) * size, (ghostY + r) * size, size, game.piece.color); } } } const m = game.piece.matrix; for (let r = 0; r < m.length; r++) { for (let c = 0; c < m[r].length; c++) { if (!m[r][c]) continue; const py = (game.piece.y + r) * size; if (py < 0) continue; // boven het bord: niet tekenen drawCell(ctx, (game.piece.x + c) * size, py, size, game.piece.color); } } } } } /* Kleine preview (hold) */ function drawHold(canvas, type) { const ctx = canvas.getContext('2d'); const cell = CONSTANTS.PREVIEW_CELL; ctx.clearRect(0, 0, canvas.width, canvas.height); if (!type) return; const shape = SHAPES[type]; const w = shape[0].length * cell; const h = shape.length * cell; const ox = (canvas.width - w) / 2; const oy = (canvas.height - h) / 2; for (let r = 0; r < shape.length; r++) { for (let c = 0; c < shape[r].length; c++) { if (!shape[r][c]) continue; drawCell(ctx, ox + c * cell, oy + r * cell, cell, CONSTANTS.COLORS[type]); } } } /* Volgende blokken onder elkaar */ function drawNext(canvas, game) { const ctx = canvas.getContext('2d'); const cell = CONSTANTS.PREVIEW_CELL; ctx.clearRect(0, 0, canvas.width, canvas.height); const list = game.preview; const band = canvas.height / CONSTANTS.PREVIEW_COUNT; for (let i = 0; i < list.length; i++) { const type = list[i]; const shape = SHAPES[type]; const w = shape[0].length * cell; const h = shape.length * cell; const ox = (canvas.width - w) / 2; const oy = i * band + (band - h) / 2; for (let r = 0; r < shape.length; r++) { for (let c = 0; c < shape[r].length; c++) { if (!shape[r][c]) continue; drawCell(ctx, ox + c * cell, oy + r * cell, cell, CONSTANTS.COLORS[type]); } } } }