let targetSize = 40; // La dimensione in pixel che desideri per ogni quadrato grosso let cellSize; let cols, rows; let grid = []; let particles = []; function setup() { // Canvas a tutto schermo createCanvas(windowWidth, windowHeight); // Inizializza la griglia per la prima volta generateDynamicGrid(); } function draw() { background(255); // 1. Gestione e disegno dei Blocchi Grossi (Quadrati perfetti a tutto schermo) for (let i = 0; i < cols; i++) { for (let j = 0; j < rows; j++) { let cell = grid[i][j]; // Controllo di sicurezza nel caso in cui la griglia si stia ridimensionando if (!cell) continue; if (cell.active) { let cellX = i * cellSize; let cellY = j * cellSize; let subSize = cellSize / 3; // Disegno sub-pixel con fusione dei bordi (no bave rosse) for (let x = 0; x < 3; x++) { for (let y = 0; y < 3; y++) { if (!cell.holes[x][y]) { stroke(cell.color); strokeWeight(1); fill(cell.color); rect(cellX + x * subSize, cellY + y * subSize, subSize, subSize); } } } if (cell.cooldown > 0) cell.cooldown--; // Interazione Mouse / Touch if (cell.cooldown === 0) { let triggered = false; if (mouseX > cellX && mouseX < cellX + cellSize && mouseY > cellY && mouseY < cellY + cellSize) { triggered = true; } if (!triggered && touches.length > 0) { for (let t of touches) { if (t.x > cellX && t.x < cellX + cellSize && t.y > cellY && t.y < cellY + cellSize) { triggered = true; break; } } } if (triggered) { let subX = floor(random(3)); let subY = floor(random(3)); triggerHoleAndPixel(i, j, subX, subY); cell.cooldown = 30; } } } } } // 2. Gestione dei pixel che cadono for (let i = particles.length - 1; i >= 0; i--) { let p = particles[i]; p.update(); if (p.gridY < rows && p.gridY >= 0) { p.display(); } else { particles.splice(i, 1); } } } // Genera la griglia calcolando quante celle servono per riempire lo schermo attuale function generateDynamicGrid() { // Calcoliamo quante colonne e righe servono approssimativamente cols = ceil(windowWidth / targetSize); rows = ceil(windowHeight / targetSize); // Adattiamo leggermente cellSize per spalmarle millimetricamente senza lasciare decimali vuoti cellSize = windowWidth / cols; grid = []; for (let i = 0; i < cols; i++) { grid[i] = []; for (let j = 0; j < rows; j++) { let isRed = random(1) < 0.6; let col = color(225, 36, 29); if (random(1) < 0.1) col = color(240, 150, 145); grid[i][j] = { active: isRed, color: col, cooldown: 0, holes: [ [false, false, false], [false, false, false], [false, false, false] ] }; } } } // Se l'utente gira lo schermo dello smartphone, rigenera la griglia per riempirlo di nuovo function windowResized() { resizeCanvas(windowWidth, windowHeight); // Svuota le particelle vecchie per evitare crash fuori griglia e ricrea la struttura particles = []; generateDynamicGrid(); } function triggerHoleAndPixel(gX, gY, subX, subY) { // Controllo di sicurezza per evitare errori se tocchi i bordi estremi durante un resize if (gX >= cols || gY >= rows || gX < 0 || gY < 0) return; let cell = grid[gX][gY]; if (cell && !cell.holes[subX][subY]) { cell.holes[subX][subY] = true; particles.push(new Particle(gX, gY, subX, subY, cell.color)); } } class Particle { constructor(gX, gY, subX, subY, col) { this.gridX = gX; this.gridY = gY; this.subX = subX; this.subY = subY; this.color = col; this.frameCounter = 0; this.frameDelay = 20; } update() { this.frameCounter++; if (this.frameCounter >= this.frameDelay) { this.frameCounter = 0; let nextRow = this.gridY + 1; if (nextRow < rows) { let options = [-1, 0, 1]; let randomOffset = random(options); let targetCol = this.gridX + randomOffset; if (targetCol >= 0 && targetCol < cols) { let targetCell = grid[targetCol][nextRow]; if (targetCell && targetCell.active && targetCell.cooldown === 0) { let nextSubX = floor(random(3)); let nextSubY = floor(random(3)); triggerHoleAndPixel(targetCol, nextRow, nextSubX, nextSubY); targetCell.cooldown = 20; this.gridY = 999; return; } } } this.gridY += 1; } } display() { let subSize = cellSize / 3; noStroke(); fill(this.color); let px = this.gridX * cellSize + this.subX * subSize; let py = this.gridY * cellSize + this.subY * subSize; rect(px, py, subSize, subSize); } } function touchMoved() { return false; }