/**
* @fileoverview Renderer und Animations-Logik für RotateBox.
*/
const COLORS = ['#e74c3c', '#2ecc71', '#f1c40f', '#3498db', '#e67e22', '#9b59b6', '#1abc9c', '#bdc3c7', '#34495e', '#f39c12'];
/**
* Zeichnet das Board auf den Canvas.
* @param {RotateBoard} board - Das Spielbrett.
* @param {HTMLCanvasElement} canvas - Das Canvas-Element.
* @param {CanvasRenderingContext2D} ctx - Der Kontext.
*/
function drawRotateBoard(board, canvas, ctx) {
if (!board || !board.grid) return;
ctx.clearRect(0, 0, canvas.width, canvas.height);
const padding = 40;
const maxDim = Math.max(board.rows, board.cols);
if (maxDim === 0) return;
const bs = (canvas.width - padding) / maxDim;
const ox = (canvas.width - (board.cols * bs)) / 2;
const oy = (canvas.height - (board.rows * bs)) / 2;
for (let r = 0; r < board.rows; r++) {
for (let c = 0; c < board.cols; c++) {
const v = board.grid[r][c];
const x = ox + c * bs;
const y = oy + r * bs;
if (v === -2) {
ctx.fillStyle = '#2c3e50';
ctx.fillRect(x, y, bs, bs);
} else if (v === -3) {
ctx.fillStyle = '#ecf0f1';
ctx.fillRect(x, y, bs, bs);
} else if (v >= 0) {
// Animation Offset beachten
const off = (board.fallOffsets && board.fallOffsets[v]) ? board.fallOffsets[v] : 0;
ctx.fillStyle = COLORS[v % COLORS.length];
ctx.fillRect(x + 1, y - (off * bs) + 1, bs - 2, bs - 2);
}
}
}
}
/**
* Animiert das Fallen der Blöcke.
* @param {RotateBoard} board
* @param {HTMLCanvasElement} canvas
* @param {CanvasRenderingContext2D} ctx
* @param {number} speed - Dummy parameter, Geschwindigkeit ist hardcoded.
* @param {function} renderCallback - Callback zum Neuzeichnen nach jedem Frame.
* @returns {Promise<void>}
*/
async function animateRelax(board, canvas, ctx, speed, renderCallback) {
board.isFalling = true;
let changed = true;
while (changed) {
changed = false;
let toFall = new Set();
// Identifizieren
for (let r = 0; r < board.rows; r++) {
for (let c = 0; c < board.cols; c++) {
const id = board.grid[r][c];
if (id >= 0 && !toFall.has(id) && board.canFall(id)) toFall.add(id);
}
}
// Animieren
if (toFall.size > 0) {
changed = true;
// Logik update
toFall.forEach(id => board.moveDown(id));
// Visuelle Interpolation
await new Promise(res => {
let off = 1.0;
function frame() {
off -= 0.15;
toFall.forEach(id => board.fallOffsets[id] = off);
renderCallback();
if (off > 0) requestAnimationFrame(frame);
else {
toFall.forEach(id => delete board.fallOffsets[id]);
res();
}
}
frame();
});
}
}
board.isFalling = false;
}