Miniguida su J2ME  

di Dersew
Definito dalla Sun Microsystems, fu' introdotto nel 1995 come linguaggio orientato agli oggetti e definito per essere trasportabile su architetture differenti e per essere eseguito da browser, il compilatore Java traduce il programma sorgente in una rappresentazione speciale detta bytecode.
Il bytecode Java non è un linguaggio macchina di una CPU particolare, ma di una macchina virtuale Java. L'interprete traduce il bytecode nel linguaggio macchina e lo esegue.
Un compilatore Java compiler non è legato ad una particolare macchina. Java è indipendente dall'architettura della macchina. J2ME (Java 2 Micro Edition) deriva da Java 2 Standard Edition J2SE, ottimizzato e "leggero" per girare su cellulari e Pda di ultima generazione. Più sinteticamente, si tratta della versione per dispositivi portatili di Java. È possibile dar vita a piccoli programmi (Generalmente di dimensione inferiore ai 100 KB), chiamati MIDLet ed eseguibili su dispositivi dotati di una Virtual Machine adatta. J2ME è una architettura che si rivolge ad una moltitudine di apparecchi anche profondamente diverse tra di loro (Telefonini, PDA, elettrodomestici, ...). per questo motivo SUN ha definito una architettura ed una serie di librerie di classi per affrontare in modo univoco la programmazione di questi dispositivi, introducendo i concetti di configurazione e di profili.
J2ME comprende due livelli di configurazione (CDC e CLDC) ed inoltre il livello "Profile" MIDP.
Un profilo è una estensione della configurazione; fornisce le librerie per permettere ai programmatori di scrivere applicazioni per un particolare tipo di dispositivo.
Il MIDP è il profilo più famoso e sara' quello trattato in questa miniguida. Prevede un sistema di GUI (Graphical User Interface), API (Application Programming Interface) di base per giochi in 2D, possibilita' di effettuare connessioni di rete, ecc. Attualmente esistono due versioni di MIDP, rispettivamente MIDP 1.0 e MIDP 2.0. MIDP 2.0 estende le funzionalita' di MIDP 1.0.

Cosa serve per iniziare?

Java 2 sdk 1.4.2 (JDK)
J2ME Wireless Toolkit (WTK) for CLDC
Un editor di testo (Scite, UltraEdit, etc.)
Documentazione J2ME (In inglese, assolutamente indispensabile)
Un po' di buona volonta' (Anch'essa indispensabile)

Per poter cominciare a creare una prima applicazione J2ME occorre quindi il J2ME Wireless Toolkit (WTK), messo a disposizione dalla Sun, che consente di compilare e testare con degli emulatori il codice che scriviamo. L'installazione del J2ME WTK richiede soltanto la presenza del Java sdk installato (JDK).
Una volta sviluppato il nostro software possiamo infine creare l'eseguibile da inviare al telefono L'applicazione da noi creata presentera' un'estenzione ".jar" e sara' accompagnata inoltre da un altro file, detto descrittore e con estensione ".jad". Il descrittore JAD viene utilizzato per eseguire dei controlli base da parte del software di gestione applicazioni del dispositivo portatile: controllo versioni, dimensioni del jar file, nome autore ecc...

La scrittura di una MIDlet è abbastanza semplice ed intuitiva.
Si deve:
1) Estendere la classe javax.microedition.midlet.MIDlet
2) Implementare i metodi startApp, pauseApp, destroyApp

  
Una prima MIDlet
import javax.microedition.midlet.MIDlet;
public class MyMIDlet extends MIDlet
{
    // Costruttore
    public MyMIDlet() {
    }// Metodi base:
    public void startApp () {
    }public void pauseApp () {
    }public void destroyApp (boolean unconditional) {
    }
}

void startApp () segnala che la MIDlet è stata posta nello stato di attivita' (Active State)
void pauseApp () segnala che la MIDlet sta entrando nello stato di pausa (Paused State)
void destroyApp (boolean unconditional) segnala che la MIDlet sta per terminare la sua esecuzione (Passando quindi al Destroyed State)

Il package javax.microedition.lcdui (User Interface Package) contiene tutte le classi per creare le interfacce utente sul display Con tali classi è possibile gestire le finestre per l'inserimento dei dati con campi di testo, selezioni a scelta multipla, date o ore in formato grafico, immagini, ecc.
Caricare un'immagine è semplice e immediato. Bisogna però gestire le eccezioni

  
Gestire le eccezioni
Image img;
try {
   img = Image.createImage("/img01.png");
} catch (Exception e) {
   // si è generata un'eccezione
   // per esempio il file "/img01.png"
   // potrebbe non esistere
}


La Classe display
Rappresenta il manager del display e dei dispositivi di input Contiene i metodi per recuperare le proprieta' del dispositivo e per richiedere che un oggetto sia visualizzato sul dispositivo C'è esattamente una solo istanza di Display per MIDlet e l'applicazione può ottenere in qualsiasi momento tale istanza tramite il metodo:

1)static Display getDisplay (MIDlet m)
2)boolean isColor () restituisce true se il dispositivo supporta i colori
3)int numColors () restituisce il numero di colori o di livelli di grigio (se isColor() è false) supportati
4)boolean vibrate (int duration) attiva la vibrazione per "duration" ms.
5)void setCurrent (Displayable nextDisplayable): imposta l'oggetto che deve essere visualizzato sul display (può essere presente solo un oggetto per volta)

La Classe displayable

La classe Displayable è la superclasse di tutti gli oggetti direttamente visualizzabili sul display Tutti gli oggetti Displayable hanno le seguenti proprieta': zero o più oggetti Command per le operazioni utente un CommandListener che riceve le notifiche di selezione dei comandi (si noti che si può impostare un solo CommandListener) la possibilita' di aggiungere un titolo ed un eventuale testo scorrevole (tramite la classe Ticker)

void addCommand (Command cmd) aggiunge un comando
int getHeight (), int getWidth () restituiscono altezza e larghezza del Displayable
boolean isShown () verifica se l'oggetto è attualmente visibile sul display
void setTicker (Ticker ticker) imposta il Ticker
void setTitle (String s) imposta il titolo del Displayable
void setCommandListener (CommandListener l) imposta il listener dei comandi

La Classe form

Un Form è uno Screen che può contenere oggetti di vario tipo (Immagini, campi di testo, campi per l'inserimento di una data, barre di progresso, etc.) In generale qualsiasi sottoclasse della classe Item può essere contenuta all'interno di un Form Costruttori:

Form(String title)
Form(String title, Item[] items)

// Dichiariamo un oggetto di tipo Form
Form form;
// Dichiariamo un oggetto di tipo Image
// Questo serve a contenere un'immagine
// In questo esempio si suppone che l'immagine
// sia caricata in un altro frammento di codice
Image logo_img;
form = new Form("Applicazione di esempio");
// Aggiungiamo quindi un testo e un immagine
form.append("Hello World!");
form.append(logo_img);
// Visualizza il nostro form sul Display
display.setCurrent(form);


La Classe Command

La classe Command definisce le operazioni che l'utente può svolgere. L'utilizzo più comune di Command è fornire un modo per navigare tra i diversi Displayable dell'applicazione. Il posizionamento, l'aspetto ed il modo di interazione dell'utente con i Command è delegato al dispositivo, Il tutto semplifica di molto il lavoro del programmatore.
Ogni Command ha un tipo ed una priorita'. Tipi e priorita' permettono al dispositivo di posizionare i Command in punti standard del display per esempio l'operazione "Indietro" potrebbe essere mappata in basso a destra.
Costruttori
Command(String label, int type, int priority)
Command(String shortLabel, String longLabel, int type, int priority)

BACK: comando per tornare allo schermo precedente
CANCEL: comando per indicare una risposta negativa
OK: comando per indicare risposta positiva
HELP: comando per l'help on line
EXIT: comando usato per uscire dall'applicazione
ITEM: comando (di item) specifico dell'applicazione
SCREEN: comando (di schermo) specifico dell'applicazione
STOP: comando per interrompere qualcosa
int getCommandType(): restituisce il tipo di comando
String getLabel(): restituisce l'etichetta breve
String getLongLabel(): restituisce l'etichetta estesa
int getPriority(): restituisce la priorita' del comando

// Creo il pulsante per uscire dalla MIDlet
Command exitCommand = new Command("Esci", Command.EXIT, 0);
// Inserisco il bottone nel form
form.addCommand(exitCommand);


Per intercettare gli eventi di comando bisogna implementare l'interfaccia CommandListener e definire il metodo void commandAction(Command c, Displayable d): il metodo lanciato quando viene attivato il comando c sul Displayable d

// Lanciato ogni volta che viene premuto il bottone
public void commandAction(Command c, Displayable d)
{
    if (c.getCommandType()==Command.EXIT)
    {
    // Distruggo l'applicazione
    destroyApp(true);
    }
};


La Classe Screen

Screen è la superclasse comune a tutti gli elementi di alto livello di una GUI in J2ME
Non aggiunge alcun metodo a Displayable e serve solo come base comune per le classi:

Alert
Form
List
TextBox


La Classe Alert

Uno Screen per la notifica di messaggi all'utente, Possono essere definiti diversi tipi di Alert a seconda dell'utilizzo che se ne deve fare,
Costruttori
Alert(String title)
Alert(String title, String alertText, Image alertImage, AlertType alertType)
alertType può assumere i valori ALARM, CONFIRMATION, ERROR, INFO, WARNING

ALARM: notifica di una particolare condizione (es. il sopraggiungere di una data)
CONFIRMATION: conferma dell'esecuzione di un'operazione (es. password inserita valida)
ERROR: notifica di una condizione di errore (es. password inserita non valida)
INFO: visualizzazione informazioni generiche
WARNING: segnalazione della potenziale pericolosita' di un'operazione richiesta (es. richiesta di cancellazione dati)

void setIndicator(Gauge indicator): imposta un eventuale indicatore di attivita' void setTimeout(int time): imposta il tempo di durata di visualizzazione (FOREVER indica durata infinita)

Quando un Alert viene chiuso l'ultimo Displayable usato viene ri-visualizzato a meno di avere usato il metodo di Display

void setCurrent(Alert alert, Displayable next): imposta alert come Displayable corrente e next come prossimo Displayable.

Alert alert = new Alert ("Il nostro Splash Screen", "Benvenuti!!", splash_img, AlertType.INFO); display.setCurrent(alert, form);

La Classe List

Uno Screen per la visualizzazione di una lista Ogni elemento ha una stringa ed una icona Possono essere definite tre tipi di liste: implicita, a scelta esclusiva ed a scelta multipla
Costruttori

List(String title, int listType) List(String title, int listType, String[] stringElements, Image[] imageElements) ListType può essere IMPLICIT, EXCLUSIVE e MULTIPLE

gli elementi della lista sono veri e propri Command e quindi lanciano eventi di comando, quando l'utente seleziona un elemento l'eventuale CommandListener associato alla lista sara' attivato, per verificare se un evento è stato lanciato da un elemento della lista bisogna controllare se il Command passato come parametro è List.SELECT_COMMAND

Liste a scelta esclusiva:
la selezione di un elemento esclude la selezione degli altri equivalenti ai gruppi di radiobutton

Liste a scelta multipla:
la selezione di un elemento non esclude la selezione degli altri equivalenti ai gruppi di checkbox

int append(String stringPart, Image imagePart): aggiunge un elemento nella lista
int getSelectedIndex(): restituisce l'indice dell'elemento selezionato
boolean isSelected(int n): verifica se l'elemento di posizione n è selezionato
int size(): restituisce il numero di elementi della lista

  
Creazione di una lista implicita
List l = new List ("La mia lista implicita", List.IMPLICIT);
l.append(" Scelta 1", img1);
l.append(" Scelta 2", img2);
l.append(" Scelta 3", img3);


ESEMPIO

  
// Lanciato ogni volta che viene premuto il bottone
public void commandAction(Command c, Displayable s)
{
    int t=c.getCommandType();
    if (t==Command.EXIT)
    {
       //Distruggo l'applicazione
       destroyApp(true);
    } //Se ho selezionato un elemento della lista
    else if (c==List.SELECT_COMMAND)
    {
       //Recupero l'indice dell'elemento selezionato
       int index = l.getSelectedIndex();
       if(index == 0) {//Imposto il form primario
       display.setCurrent(form);
       }
       else { //Imposto il form secondario
       display.setCurrent(form2);
       }
    }
}


La Classe texbox

Uno Screen per l'inserimento di testo. Possono essere definiti diversi tipi di TextBox a seconda dell'utilizzo che se ne deve fare
Costruttore

TextBox(String title, String text, int maxSize, int constraints) constraints può essere ANY, DECIMAL, EMAILADDR, NUMERIC, PASSWORD, PHONENUMBER, URL

ANY: l'utente può inserire qualsiasi valore
DECIMAL: l'utente può inserire solo valori numerici decimali
EMAILADDR: i dati rappresentano una email
NUMERIC: l'utente può inserire solo valori interi
PASSWORD: i dati rappresentano una password
PHONENUMBER: i dati rappresentano un numero telefonico
URL: i dati devono rappresentare un URL
String getString(): restituisce il testo della TextBox
void setString(String text): imposta il testo della TextBox
void delete(int offset, int length): cancella una parte del testo
void insert(String src, int position): inserisce un testo
int setMaxSize(int maxSize): imposta il massimo numero di caratteri accettati
int size(): restituisce il numero di caratteri attualmente contenuti nella TextBox

L'utilizzo delle API di alto livello per la creazione delle GUI (Graphic User Interface) fornisce la massima portabilita' e facilita' di sviluppo Tuttavia alcune applicazioni richiedono un controllo più fine sulla GUI L'API di basso livello per la creazione delle GUI è progettata per quelle applicazioni che necessitano invece di posizionamento e controllo preciso degli elementi grafici e di un accesso a basso livello agli eventi di input
Tipici esempi di componenti che dovrebbero necessitare di tale approccio sono un game board, un diagramma, un grafico, ecc.
Usando tale API un'applicazione può:

Controllare con precisione cosa è disegnato sul display
Gestire gli eventi di basso livello (keypressed, keyreleased, ecc.)
Accedere direttamente alle key (tasti, softkey, ecc.) ed ad altri dispositivi di input

Per utilizzare direttamente l'API di basso livello bisogna conoscere le classi Graphics e Canvas
Graphics ci fornisce metodi per disegnare rettangoli, archi, scrivere testo, impostare il colore degli elementi, conoscere le dimensioni del display e i colori disponibili ecc.
Canvas invece fornisce:

La "superficie" e le dimensioni del display
Le callback usate per gestire gli eventi ed i metodi per disegnare sul display

La combinazione della capacita' di gestire gli eventi del Canvas e delle capacita' di disegno del Graphics permette di avere il completo controllo sullo schermo
Queste classi possono essere usate per esempio per:

Creare nuovi schermi personalizzati
Implementare videogame
Manipolare immagini

Un Canvas non deve necessariamente avere accesso all'interno schermo di un dispositivo J2ME, Certe aree dello schermo possono essere riservate per altri scopi (ad esempio visualizzare lo stato della rete o della batteria), Inoltre l'uso di un titolo, di un Ticker e/o di oggetti Command possono ulteriormente ridurre lo spazio disponibile al Canvas.

Le dimensioni di un Canvas possono essere ottenute tramite i metodi di Displayable:
int getWidth(), int getHeight()
Inoltre si può essere informati quando le dimensioni variano per qualche motivo tramite il metodo:
void sizeChanged(int w, int h): lanciato quando variano le dimensioni del Canvas
Ciò permette di (eventualmente) riadattare in tempo reale il layout dell'applicazione

Se un'applicazione vuole una visualizzazione a tutto schermo allora bisogna lanciare il metodo void setFullScreenMode(boolean mode): attiva/disattiva la visualizzazione a tutto schermo Alcuni dispositivi potrebbero anche nascondere gli indicatori di stato del sistema

Per dire al dispositivo cosa deve disegnare in un Canvas bisogna implementare il metodo
void paint(Graphics graphics): descrive cosa deve essere disegnato nel Canvas
Quando si vuole che un Canvas si ridisegni non si deve chiamare direttamente tale metodo, ma il metodo: void repaint(): forza il ridisegno del Canvas

In J2ME i colori possono essere definiti solo:

come terne di interi RGB
come un unico intero opportunamente formattato (0x00RRGGBB)

Esiste il solo modello di colore RGB
Non esiste il concetto di trasparenza

Per impostare il colore della classe Graphics bisogna usare i metodi:
void setColor(int RGB),
void setColor(int red, int green, int blue):
impostano il colore della classe Graphics
Dopo questo comando tutto ciò che verra' disegnato usera' il colore specificato
Il colore di default è il nero!

Le stringhe in J2ME vengono "disegnate" mediante la classe Font contenente tutte le caratteristiche tipografiche necessarie. Tale classe può richiamare solo un numero limitato di font standard. È possibile impostare gli stili corsivo, grassetto e sottolineato ed ovviamente la dimensione del font
Per definire un Font si possono utilizzare i seguenti metodi statici:

Font getDefaultFont(): restituisce il font di default del dispositivo
Font getFont(int fontSpecifier): restituisce un font standard del dispositivo (fontSpecifier può essere FONT_INPUT_TEXT, FONT_STATIC_TEXT)
Font getFont(int face, int style, int size): restituisce un font ad hoc

Face può essere FACE_SYSTEM, FACE_MONOSPACE, FACE_PROPORTIONAL
Style può essere STYLE_PLAIN, o una combinazione di STYLE_BOLD, STYLE_ITALIC e STYLE_UNDERLINED
Size può essere SIZE_SMALL, SIZE_MEDIUM, SIZE_LARGE
Per impostare il Font bisogna usare il metodo void setFont(Font f): imposta il Font del contesto grafico

In J2ME esistono tre diversi tipi di eventi di basso livello
Key Event: eventi generati dalla pressione dei tasti della tastiera del dispositivo
Action Event: particolari key event collegati con dei tasti appositi per i giochi
Pointer Event: eventi generati da dispositivi di puntamento

Key Event

Gestire i Key Event di un Canvas significa implementare i metodi
void keyPressed(int keyCode): lanciato quando un tasto viene premuto
void keyReleased(int keyCode): lanciato quando un tasto viene rilasciato
void keyRepeated(int keyCode): lanciato quando un tasto viene tenuto premuto

Ovviamente in J2ME esistono delle costanti per identificare i vari tasti
Tali costanti sono definite nella classe Canvas
KEY_NUM0, ..., KEY_NUM9: identificano i numeri da 0 a 9
KEY_POUND: identifica il tasto "#"
KEY_STAR: identifica il tasto "*"


La classe Canvas dispone inoltre di alcuni metodi per gestire in maniera portabile gli Action Event (anche chiamati Game Action) L'API definisce un insieme di costanti che possono essere mappate dall'implementazione MIDP su particolari tasti del dispositivo Tali costanti sono: UP, DOWN, LEFT, RIGHT, FIRE, GAME_A, GAME_B, GAME_C e GAME_D
Una applicazione può individuare il corretto codice di Action Event generato tramite il metodo int getGameAction(int keyCode): restituisce il codice dell'Action Event
Se invece dato un codice di Action Event si vuole conoscere un codice di Key Event associato si deve usare il metodo: int getKeyCode(int gameAction): restituisce un codice di Key Event associato al codice di Action Event

Pointer Event

I palmari e gli smart phone solitamente sono dotati di particolari dispositivi di puntamento (ad esempio i pennini)
La classe Canvas ha dei metodi che permettono di gestire gli eventi generati da tali dispositivi
void pointerPressed(int x, int y): lanciato quando il puntatore viene premuto sul display
void pointerReleased(int x, int y): lanciato quando il puntatore viene sollevato dal display
void pointerDragged(int x, int y): lanciato quando il puntatore viene trascinato sul display

Ovviamente non tutti i dispositivi supportano queste caratteristiche e quindi non supporteranno nemmeno i Pointer Event È possibile comunque sapere se un dispositivo supporta o meno tali eventi tramite i metodi
boolean hasPointerEvents(): verifica se il dispositivo supporta i Pointer Event di pressione e rilascio
boolean hasPointerMotionEvents(): verifica se il dispositivo supporta i Pointer Event di trascinamento

L'api per i giochi

I video game si sono dimostrati essere i tipi di applicazioni J2ME più usati, Per tale ragione nella versione MIDP 2.0 è stata inserita un'intera libreria specificatamente progettata per lo sviluppo di video giochi. Tale libreria si trova nel package javax.microedition.lcdui.game
Questa API fornisce molte facilitazioni per lo sviluppatore:

1)Semplifica lo sviluppo e fornisce un ambiente più familiare agli sviluppatori di video game
2)Ciduce la dimensione e la complessita' dell'applicazione fornendo funzionalita' e metodi altrimenti da sviluppare a mano
3)Poiché l'API può essere implementata usando codice nativo essa potrebbe incrementare le performance finali

Il package.javax.microedition.lcdui.game

GameCanvas:
fornisce le funzionalita' per la gestione di base dello schermo (estende Canvas),in generale semplifica lo sviluppo ed aumenta le performance
Layer:
una delle novita' più consistenti introdotte con queste API,permette di isolare un elemento grafico dal contesto grafico e gestirne in questo modo la posizione, la dimensione e la visibilita'
LayerManager:
classe di servizio che facilita la gestione dei Layer, indispensabile quando si utilizza un considerevole numero di oggetti Layer
Sprite:
la classe più utilizzata quando si sviluppa un gioco, permette di gestire più immagini in un'unica immagine, in modo da semplificarne l'utilizzo e ridurne la dimensione (una PNG 100x10 è più leggera di 10 PNG 10x10)
TiledLayer:
permette di gestire un'area sullo schermo composta da tante "mattonelle" che possono essere tante immagini diverse in questa maniera si possono realizzare delle interessanti animazioni di sfondo per i giochi che si vogliono sviluppare

La Classe layer

La classe astratta Layer rappresenta l'entita' base che può essere visualizzata sullo schermo, Un Layer ha un suo bound rettangolare e può essere visibile o invisibile, può essere renderizzato usando un qualsiasi oggetto Graphics e chiamando il suo metodo void paint(Graphics g): disegna il Layer

La classe Layer ha due sottoclassi:
Sprite
TiledLayer

Sfortunatamente la classe Layer non può essere sottoclassata dal programmatore,Questo poiché potrebbe compromettere l'abilita' di incrementare le performance tramite l'uso di codice nativo nelle API
Le sottoclassi di Layer possono essere disegnate in qualsiasi momento,Tale disegno utilizzera' le informazioni del Layer stesso (posizione, visibilita', ecc.), La posizione del Layer è sempre relativa all'attuale origine delle coordinate dell'oggetto Graphics
int getWidth(), int getHeight(): restituiscono larghezza ed altezza del Layer
int getX(), int getY(): restituiscono la posizione del Layer
void setPosition(int x, int y): imposta la posizione del Layer
void move(int dx, int dy): muove il Layer
boolean isVisible(): restituisce la visibilita' del Layer
void setVisible(boolean b): imposta la visibilita' del Layer

La Classe sprite

In qualsiasi gioco di successo un contributo fondamentale viene dato dalla qualita' grafica, Molti degli oggetti in un gioco vengono "categorizzati" come uno speciale tipo di grafica detto sprite. Un sprite può essere qualsiasi cosa: un proiettile, un mostro, il personaggio del gioco, item di energia o danneggiamento, chiavi, porte, ecc.
Solitamente gli sprite sono animati, Tale animazione è ottenuta tramite una sequenza di immagini dello stesso sprite ognuna leggermente diversa dalle altre per simulare l'animazione, Ogni immagine di questo insieme è solitamente chiamata frame,Questi frame possono essere visualizzati in sequenza o meno.

Esistono tre costruttori

Sprite(Image image): crea un sprite non animato a partire da un'immagine
Sprite(Image image, int frameWidth, int frameHeight): crea uno sprite animato a partire da un'immagine; ogni singolo frame è individuato da un intero univoco ed ha dimensione frameWidthxframeHeight
Sprite(Sprite s): crea uno sprite da un altro sprite

Per disegnare uno sprite è sufficiente chiamare il suo metodo paint, ovviamente lo sprite deve essere visibile; Per ottenere un'animazione bisogna invece impostare una sequenza di frame. La classe Sprite mette a disposizione una serie di metodi per questo scopo:

void setFrameSequence(int[] sequence): imposta la sequenza di frame
int getFrameSequenceLength(): restituisce la lunghezza della sequenza
int getFrame(): restituisce l'indice del frame attuale
void nextFrame(): passa al frame successivo
void prevFrame(): torna al frame precedente
void setFrame(int sequenceIndex): imposta il frame corrente

Sprite sprite;
Image img;
public MyCanvas()
{
    try {
       img = Image.createImage("/frames.gif");
    } catch (Exception e) { }
    sprite = new Sprite(img, img.getWidth()/3, img.getHeight());
    sprite.setPosition (30, 20);
}
protected void paint(Graphics g) {
    sprite.paint(g);
    sprite.nextFrame();
    repaint();
}


Note: Miniguida Realizzata Da Ðersew, per suggerimenti o correzioni: Mail
(spero sia stata di vostro gradimento e abbiate imparato qualcosa di utile..bye)

Ecco cosa pensano le persone...
Loggati e scrivi il tuo commento, e' molto importante per noi conoscere il tuo parere sui nostri articoli, grazie.



Powered by HackRoom
Attendere il caricamento...
Attendere il caricamento del vostro profilo...
Inserisci almeno due lettere
Attendere il caricamento...
Attendere il caricamento...