Di applet Java che hanno fatto la storia ce ne sono molte ed oggi, anche se passano via via in disuso per essere sostituite da animazioni flash, questo tipo di programmi offrono sempre lo spunto per nuovi giochi divertenti che possono essere inseriti in una pagina web. In questo articolo vedremo, a puro scopo didattico per spiegare come funziona un’applet Java ed in particolare la manipolazione dei pixel, come è possibile creare una famosissima, vecchissima e conosciutissima applet Java che ci consente di incendiare un’immagine che inseriremo come parametro, effetto fuoco molto carino con le scritte, in particolare testo chiaro su sfondo scuro.
L’applet che andremo a scrivere manipolerà un’immagine appiccando le fiamme a ciò che vi è contenuto, ecco i passi che implementeremo:
Ecco il risultato a cui arriveremo:
ed ecco il codice che serve per arrivare a tale risultato:
import java.awt.*; import java.awt.image.*; import java.applet.*; public class Fuoco extends Applet implements Runnable { Image buffer; Thread thread; ColorModel colorModel; int w, h, p; int[] mappa, destinazione, lavoro; int[] valoriRandom; public void init() { createColorModel(); valoriRandom = new int[600]; for (int i = 0; i < valoriRandom.length; i++) valoriRandom[i] = (int)Math.floor(Math.random() * 255); } private void createColorModel() { byte ind1[] = new byte[255]; byte ind2[] = new byte[255]; byte ind3[] = new byte[255]; for (int i = 0; i < 255; i++) ind1[i] = (byte)i; for (int i = 0; i < 255; i++) ind2[i] = (i <= 128) ? 0 : (byte)(2 * (i - 128)); for (int i = 0; i < 255; i++) ind3[i] = (i <= 192) ? 0 : (byte)(2 * (i - 64)); colorModel = new IndexColorModel(8, 255, ind1, ind2, ind3); } public void start() { if (thread == null) { thread = new Thread(this); thread.start(); } } public void stop() { thread = null; } public void run() { String imageName = getParameter("image"); if (imageName == null) { notificaErrore("Parametro 'image' non specificato"); return; } Image image; try { MediaTracker mt = new MediaTracker(this); image = getImage(getDocumentBase(), imageName); mt.addImage(image, 0); mt.waitForID(0); } catch (Exception e) { notificaErrore("Impossibile caricare l'immagine"); return; } w = image.getWidth(null); h = image.getHeight(null); p = w * h; int[] origine = new int[p]; try { new PixelGrabber(image, 0, 0, w, h, origine, 0, w).grabPixels(); } catch (Exception e) { return; } mappa = new int[p]; for (int i = 0; i < p; i++) { int r = (origine[i] & 0xff0000) >> 16; int g = (origine[i] & 0xff00) >> 8; int b = (origine[i] & 0xff); int media = (r + g + b) / 3; if (media > 128) mappa[i] = (int)(Math.random() * 128) + 127; } destinazione = new int[p]; for (int i = 0; i < p; i++) destinazione[i] = 0; lavoro = new int[p]; for (int i = 0; i < p; i++) lavoro[i] = mappa[i]; try { int i = 0; while (thread != null) { long t = System.currentTimeMillis(); brucia(); buffer = createImage(new MemoryImageSource(w, h, colorModel, destinazione, 0, w)); repaint(); i++; if (i > 50) { System.gc(); i = 0; } Thread.sleep(Math.max(25 - (System.currentTimeMillis() - t), 0)); } } catch (Exception e) { } } private void brucia() { int c = (int)Math.floor(Math.random() * 255); for (int i = 1; i < p - w; i++) { if (c > 490) c = 0; int sotto = i + w; int sinistra = i - 1; int destra = i + 1; if (lavoro[sotto] != 0 || lavoro[sinistra] != 0 || lavoro[destra] != 0) { int disc; int aux = valoriRandom[c++] % 5; if (aux > 2) disc = 0; else if (aux > 0) disc = 1; else disc = -1; int p1 = i + disc; int p2 = (valoriRandom[c++] % 20) + 235; int p3 = valoriRandom[c++] % 5; switch (p3) { case 0: lavoro[p1] = (lavoro[destra] * p2) / 255; break; case 1: lavoro[p1] = (lavoro[sinistra] * p2) / 255; break; default: lavoro[p1] = (lavoro[sotto] * p2) / 255; break; } if (lavoro[p1] * 3 < mappa[p1] << 1) lavoro[p1] = mappa[p1]; } } for (int i = 0; i < p; i++) destinazione[i] = destinazione[i] + lavoro[i] >> 1; } public void repaint() { paint(getGraphics()); } public void paint(Graphics g) { if (buffer != null) g.drawImage(buffer, 0, 0, null); } private void notificaErrore(String s) { showStatus(s); } }
Cercate di non fare il classico copia e incolla, questo articolo è scritto a solo scopo didattico, questa applet la trovate ovunque in Internet, cercate piuttosto di capire i singoli passaggi e poi cercate di riproporre lo stesso risultato anche con vostre implementazioni. All’interno del metodo init, che tutte le applet hanno come funzione di avvio, creiamo il modello di rappresentazione dei colori con il metodo createColorModel, questo dovrà essere applicato ad ogni fotogramma. Ciascun pixel verrà infuocato solo se la media delle sue componenti RGB supera il valore di 128, variando questo parametro potete ottenere aree infuocate più o meno vaste. Sicuramente la funzione più complicata è brucia, che passa in rassegna i dati conservati in lavoro, per ogni pixel vengono valutati i punti adiacenti, il colore delle aree più calde viene intensificato. A calcolo concluso tutto viene trasferito su destinazione, utilizzato per la generazione dell’immagine definitiva.
Per visualizzare l’applet in azione avremo bisogno anche di una pagina web il cui codice è:
<html> <head><title>Fuoco!</title></head> <body bgcolor="#000000"> <div align="center"> <applet code="Fuoco.class" width="300" height="200"> <param name="image" value="Fuoco.gif"> </applet> </div> </body> </html>
Dopo aver compilato l’applet e creato la pagina web, inserite un’immagine, nello stesso percorso, con una scritta chiara su fondo scuro e poi aprite la pagina web, avrete così il risultato che vi ho mostrato in precedenza.
Sono arrivato alla convinzione che un abbonamento per tutti i miei software gestionali sia il…
MerciGest è un software per la gestione del magazzino completamente gratuito. Continua a leggere→
In ufficio può capitare di doversi allontanare dal proprio posto di lavoro, ecco che allora…
In questo articolo vedremo quando è più o meno utile togliere la corrente ad un…
Dopo la pausa invernale dovuta al lavoro che devo fare per sostentarmi, eccomi di nuovo…
Vediamo come eliminare i files direttamente da Windows senza utilizzare il cestino. Continua a leggere→