import java.awt.*;
import java.applet.Applet;
public class otto extends Applet implements Runnable {
/* Dimensioni previste dell'applet */
private final int MAXX = 240;
private final int MAXY = 240;
/* Dimensioni della pallina */
private final int DIMX = 24;
private final int DIMY = 24;
private final int STEP = 10; /* Singolo movimento in pixel pallina verde*/
private final int RSTEP = 20; /* Singolo movimento in pixel pallina rossa*/
/* Costanti per la direzione del movimento */
private final int E = 0;
private final int S = 1;
private final int N = 2;
private final int W = 3;
/* Coordinate correnti della pallina verde */
private int x = MAXX / 3;
private int y = 0;
/* Variabile di stato: direzione corrente pallina verde */
private int dir = E;
/* Coordinate correnti della pallina rossa */
private int xr = 0;
private int yr = MAXY / 2;
/* Variabile di stato: direzione corrente pallina rossa */
private int dirr = E;
/* Array delle velocita' delle due palline */
private int speed [] = { STEP, RSTEP};
private Image dot = null; /* La pallina verde */
private Image rdot = null; /* La pallina rossa */
private volatile boolean sem1 = false; /* Semaforo di sinistra */
private volatile boolean sem2 = false; /* Semaforo di desrtra */
Thread avanza = null; /* Thread della pallina verde */
Thread ravanza = null; /* Thread della pallina rossa */
/* Init deve solamente lanciare il caricamento delle palline */
public void init () {
dot = getImage(getCodeBase(), "lista.gif");
rdot = getImage(getCodeBase(), "listarossa.gif");
}
/* Deve far partire l'animazione */
public void start() {
/* Thread della pallina verde */
if (avanza == null) { // Se il thread non esiste ancora
avanza = new Thread(this, "lista"); // Lo crea
avanza.start(); // E lo fa partire
}
/* Thread della pallina rossa */
if (ravanza == null) { // Se il thread non esiste ancora
ravanza = new Thread(this, "listarossa"); // Lo crea
ravanza.start(); // E lo fa partire
}
}
/* Movimento pallina verde */
private synchronized void ballMove () {
switch (dir) { // A seconda dllo stato (la direzione corrente)
case E : // Verso Est
x += STEP; // Aumenta la X
if (x >= (2 * MAXX) / 3) { // Se arriva al bordo destro
dir = S; // Cambia direzione (va a Sud)
}
break;
case S : // Verso Sud
y += STEP; // Aumenta la Y
/* Gestione dell'incorcio destro e del semaforo destro */
if (y >= (MAXY / 2) - DIMY &&
y < (MAXY / 2) - DIMY + STEP) { // Entra nella zona di scontro
if (sem2) { // Se il semaforo destro e' rosso
try {
wait (); // (attende sull'applett) Attende il verde
} catch (Exception e) {
}
}
sem2 = true; // Accende il semaforo destro
} else if (y >= (MAXY / 2) + DIMY &&
y < (MAXY / 2) + DIMY + STEP) { // Esce dalla zona di scontro
sem2 = false; // Spegne il semaforo destro
notifyAll (); // Sblocca i thread in attesa su quel semaforo
}
if (y >= (2 * MAXY) / 3) { // Se arriva al bordo inferiore
dir = W; // Cambia direzione (va a Ovest)
}
break;
case W : // Verso Ovest
x -= STEP; // Cala la X
if (x <= MAXX / 3) { // Se arriva al bordo sinistro
dir = N; // Cambia direzione (va a Nord)
}
break;
case N : // Verso Nord
y -= STEP; // Cala la Y
/* Gestione dell'incorcio sinistro e del semaforo sinistro */
if (y >= (MAXY / 2) + DIMY &&
y < (MAXY / 2) + DIMY + STEP) { // Entra nella zona di scontro
if (sem1) { // Se il semaforo sinistro e' rosso
try {
wait (); // (attende sull'applett) Attende il verde
} catch (Exception e) {
}
}
sem1 = true; // Accende il semaforo sinistro
} else if (y >= (MAXY / 2) - DIMY &&
y < (MAXY / 2) - DIMY + STEP) { // Esce dalla zona di scontro
sem1 = false; // Spegne il semaforo sinistro
notifyAll (); // Sblocca i thread in attesa su quel semaforo
}
if (y <= 0) { // Se arriva al bordo superiore
dir = E; // Cambia direzione (va di nuovo a Est)
}
break;
};
}
/* Movimento pallina verde */
private synchronized void rballMove () {
switch (dirr) {
case E : // Verso Est
xr += RSTEP; // Aumenta la X
/* Gestione dell'incorcio sinistro e del semaforo sinistro */
if (xr >= (MAXX / 3) - DIMX &&
xr < (MAXX / 3) - DIMX + RSTEP) { // Entra nella zona di scontro
if (sem1) { // Se il semaforo sinistro e' rosso
try {
wait (); // (attende sull'applett) Attende il verde
} catch (Exception e) {
}
}
sem1 = true; // Accende il semaforo sinistro
} else if (xr >= (MAXX / 3) + DIMX &&
xr < (MAXX / 3) + DIMX + RSTEP) { // Esce dalla zona di scontro
sem1 = false; // Spegne il semaforo sinistro
notifyAll (); // Sblocca i thread in attesa su quel semaforo
}
/* Gestione dell'incorcio destro e del semaforo destro */
if (xr >= (2 * MAXX / 3) - DIMX &&
xr < (2 * MAXX / 3) - DIMX + RSTEP) { // Entra nella zona di scontro
if (sem2) { // Se il semaforo destro e' rosso
try {
wait (); // (attende sull'applett) Attende il verde
} catch (Exception e) {
}
}
sem2 = true; // Accende il semaforo destro
} else if (xr >= (2 * MAXX / 3) + DIMX &&
xr < (2 * MAXX / 3) + DIMX + RSTEP) { // Esce dalla zona di scontro
sem2 = false; // Spegne il semaforo destro
notifyAll (); // Sblocca i thread in attesa su quel semaforo
}
if (xr >= MAXX) { // Se arriva al bordo inferiore
dirr = S; // Cambia direzione (va a Sud)
}
break;
case S : // Verso Sud
yr += RSTEP; // Aumenta la Y
if (yr >= MAXY) { // Se arriva al bordo inferiore
dirr = W; // Cambia direzione (va a Ovest)
}
break;
case W : // Verso Ovest
xr -= RSTEP; // Cala la X
if (xr <= 0) { // Se arriva al bordo sinistro
dirr = N; // Cambia direzione (va a Nord)
}
break;
case N : // Verso Nord
yr -= RSTEP; // Cala la Y
if (yr <= MAXY / 2) { // Se arriva al bordo superiore
dirr = E; // Cambia direzione (va di nuovo a Est)
}
break;
};
}
/* Metodo che esegue il 'lavoro duro' - azione */
public void run() {
// Questo metodo viene invocato per ogni thread dell'Applet, quindi deve
// eseguire il lavoro solo nel caso il thread sia quello dell'animazione,
// uno o l'altro
if (Thread.currentThread() == avanza) { // Thread pallina verde
// Il loop termina quando l'attributo avanza viene messo a null in stop()
while (avanza!= null) {
ballMove (); // Movimento pallina verde - gestisce semaforo
repaint(); // Ridisegna il cmapo
try {
Thread.sleep(100); // Attende 100 mS
} catch (InterruptedException e){ // Nessuna azione
}
}
} else if (Thread.currentThread() == ravanza) {
// Il loop termina quando l'attributo ravanza viene messo a null in stop()
while (ravanza!= null) {
rballMove (); // Movimento pallina rossa - gestisce semaforo
repaint(); // Ridisegna il cmapo
try {
Thread.sleep(100); // Attende 100 mS
} catch (InterruptedException e){ // Nessuna azione
}
}
}
}
/* Se usciamo dalla pagina, elimina il thread */
public void stop() {
avanza = null; // se 'avanza' diventa 'null', il metodo 'run' (istanza pallina verde) termina
ravanza = null; // se 'avanza' diventa 'null', il metodo 'run' (istanza pallina rossa) termina
}
/* Funzione di disegno che semplicemente disegna le palline alle coordinate fissate ed i semafori */
synchronized public void paint(Graphics g) {
g.drawImage (dot, x, y, this); // Pallina verde
g.drawImage (rdot, xr, yr, this); // Pallina rossa
g.setColor ((sem1) ? Color.red : Color.green); // Colore semaforo sinistro
g.fillRect (MAXX/3 - 20, MAXY / 2 - 20 , 10 , 10); // Semaforo sinistro
g.setColor ((sem2) ? Color.red : Color.green); // Colore semaforo destro
g.fillRect (2*MAXX/3 + 10 + DIMX, MAXY / 2 - 20 , 10 , 10);// Semaforo destro
}
}