PDA

View Full Version : [JAVA]Problema di ArrayList di oggetti classe


Donbabbeo
15-09-2008, 17:24
Spero che si capisca il titolo, ho buttato là una specie di pseudo descrizione del problema, visto che non so se ciò che cerco ha un nome specifico :O

Sto creando un'applicazione grafica pseudo-gioco e sto facendo alcuni test preliminari, in pratica creo degli oggetti Entity (nient'altro che delle palline), che è una classe da me definita così:

/** Posizione x dell'entità */
protected int x;
/** Posizione y dell'entità */
protected int y;

/** Velocità orizzontale dell'entità */
protected double dx = 3;
/** Velocità verticale dell'entità */
protected double dy = 3;
/** Raggio della sfera */
int radius = 8;

public Entity(int x,int y)
{
this.x = x;
this.y = y;
}
public void move(int i, int j, int larg, int alt)
{ ... }


In pratica posso inizializzare una sfera in un qualsiasi punto dello schermo ed impostarne il moto, scegliendo se muoverla in orizzontale, verticale o diagonale, in quale direzione deve muoversi ed entro quali limiti.

Funziona alla perfezione (dopotutto sono 10 righe di codice :D ) finchè devo inizializzarne ciascuna separatamente... il fatto è che volevo farlo in modo iterativo creando un arraylist di Entity dove inserire ciascuno che creo, qualcosa del genere:
/** Lista entità sfera */
ArrayList<Entity> entityList = new ArrayList<Entity>();
for (int i = 0; i < 4; i++)
{
//Tanto per dire eh, così non funziona
entityList.add(i*50,i*50);

}
e dentro il mainLoop qualcosa del genere
for (int i = 0; i < 4; i++)
{
entityList.move(dirOrizzontale, dirVerticale, LarghezzaSchermo, AltezzaSchermo);

}

Si capisce che voglio fare? :mc:
Vorrei inserire degli oggetti inizializzati ad un arraylist di tali oggetti e richiamarne le funzioni direttamente selezionandoli dall'arrayList. Possibile?
Immagino di si ma non so dove metterci le mani :help:

pequeno
15-09-2008, 20:44
A prima vista non funziona perchè dovresti passare all'ArrayList un parametro che sia il riferimento ad un oggetto... non i due argomenti previsti dal costruttore di Entity...

pequeno
15-09-2008, 20:55
Il codice che hai postato dovrebbe diventare...

/** Lista entità sfera */
ArrayList<Entity> entityList = new ArrayList<Entity>();
for (int i = 0; i < 4; i++) { ;
entityList.add(new Entity(i*50, i*50));
}


e nel main..


for (Entity elemento:entityList) {
elemento.move(dirOrizzontale, dirVerticale, LarghezzaSchermo, AltezzaSchermo);
}


ovviamente avendo il riferimento alla lista creata dall'altro metodo e i parametri corretti.. dirOrizzontale, dirVerticale, etc. etc.

banryu79
16-09-2008, 08:31
Donbabbeo, pequeno ha ragione.

/** Lista entità sfera */
ArrayList<Entity> entityList = new ArrayList<Entity>();
for (int i = 0; i < 4; i++) { ;
entityList.add(new Entity(i*50, i*50));
}


Il fatto che tu abbia dichiarato una ArrayList<Entity> (usando così i Generics) invece della semplice ArrayList (che invece non è tipizzata e accetta quindi qualsiasi Object) non significa che basti invocare il metodo .add() per invocare implicitamente il costruttore di un nuovo oggetto di tipo Entity (e vorrei anche vedere :D )

Devi comunque creare ogni singolo oggetto Entity, prima di poterlo aggiungere alla tua ArrayList<Entity>.

Il vantaggio (tanto per citarne uno) di aver dichiarato la "versione a tipo parametrico":

ArrayList<Entity> entityList;


Invece che la versione "non tipizzata":

ArrayList entityList;


E' che quanto chiamerai una .get(index) sulla tua lista ti verrà restituito un reference all'oggetto del tipo giusto (Entity) invece di un reference a Object che dovresti quindi castare a Entity.

Inoltre con la versione Generics della tua Collection puoi utilizzare i cicli "for each" introdotti dalla versione 1.5 e scrivere così cicli for più snelli ed eleganti. Vedi qui (http://java.sun.com/j2se/1.5.0/docs/guide/language/foreach.html) per maggiori info.
Per i Generics c'è questo (http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf)
Ciao.

Donbabbeo
16-09-2008, 10:45
Innanzitutto grazie ad entrambi, come penso si sia capito sono un vero caprone con queste cose... :muro:

Purtroppo non mi riesce di farlo andare :cry:
Ho provato anche ad usare un classico array, visto che so il numero di oggetti da creare fin dal principio, ma dà un errore di eccezione...

In pratica sto creando uno sfondo animato, ho una classe Space fatta così:

package Space;

import java.awt.Graphics;
import java.awt.Color;

/** Implementa un quadrato che si muove */

public class Space extends Entity
{
/** Velocità dell'entità in verticale */
protected double dy = 2;
/** Dimensione entità */
protected int radius = 2;

/** Costruttore */
public Space(int x, int y)
{
super(x, y);
}

/** Muovi la stella verso il basso,
* al raggiungimento del bordo inferiore
* riprendi il cammino dall'alto */
public void move(int altezza)
{
this.y += dy;

if (this.y > altezza)
this.y = 0;
}

/** Disegna la stella */
public void draw(Graphics g)
{
int posX, posY;

posX = this.x;
posY = this.y;

g.setColor(Color.WHITE);
g.fillRect(posX, posY, radius, radius);
}
}

La classe da cui deriva ha il costruttore così composto:

public Entity(int x,int y)
{
this.x = x;
this.y = y;
}

L'errore se ho ben capito dovrebbe essere che definisco nella main l'istanza della classe Space come array così:
/** Lista entità stelle */
Space space[];

che viene poi inizializzata così:
for (int i = 0; i < 50, i++)
space[i] = new Space(i * 2, i * 2);

Invece dovrei definire una lista di classi Space giusto? Peccato che non mi riesca :cry:
Scusate se abuso della vostra pazienza ma sono davvero niubbo :(

banryu79
16-09-2008, 11:06
L'errore nell'utilizzo dell'array è dato dal fatto che qui dichiari una reference ad un array di oggeti Space:

/** Lista entità stelle */
Space space[];

Ma questa appunto è una semplice dichiarazione del fatto che la reference di nome "space" è un riferimento ad un array di dimensioni non note di oggetti Space, ma l'array di per se non viene creato/istanziato in memoria, ancora non esiste per cui quando fai:

for (int i = 0; i < 50, i++)
space[i] = new Space(i * 2, i * 2);

space[i] ti da un errore perchè stai usando una reference (space) che non è stata ancora inizializzata, quindi il compilatore giustamente si lamenta perchè non sa che pesci pigliare ... :D

Basta che inizializzi space a null per esempio.

/** Lista entità stelle */
Space space[] = null;


Ciao :)

pequeno
16-09-2008, 11:07
Invece dovrei definire una lista di classi Space giusto? Peccato che non mi riesca :cry:
Scusate se abuso della vostra pazienza ma sono davvero niubbo :(

Semmai una lista di riferimenti ad oggetti della classe Space...
Cmq potresti postare o inviarmi il codice delle classi che hai creato, così ti indico come fare?

P.S. Per convezione del linguaggio i nomi dei package andrebbero scritti sempre tutti in minuscolo e i nomi dei metodi secondo la notazione cammello..

Es.
// package della classe
package it.space.modello;

// metodo della classe
public void metodoEseguiQualcosa() {}

Donbabbeo
16-09-2008, 13:36
Banryu ho provato a fare come dici tu ma sebbene compili correttamente continua a segnalarmi l'errore:
Exception in thread "main" java.lang.NullPointerException
at Space.MainWindow.init(MainWindow.java:69)
at Space.MainWindow.gameLoop(MainWindow.java:82)
at Space.MainWindow.main(MainWindow.java:145)

Comunque ora posto il codice completo, è poca roba e scritta nel modo più intuitivo possibile, spero non porti via troppo tempo cercare di capirlo.
PS: Grazie mille ancora una volta :D

Breve descrizione:
Sto creando una specie di videogioco, qualcosa tipo space invaders o breakout o una via di mezzo tra i 2 :asd:.
PS: nel main ci sono un bordello di librerie, fate finta che siano solo le necessarie, ho ripreso un vecchio file che avevo e non le ho ancora sistemate :D
PSS: il package è con la maiuscola perchè senza mi da un sacco di errori :confused:

MainWindow.java
contiene la logica del programma e l'inizializzazione del frame
package Space;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.lang.*;
import java.awt.*;
import java.text.DecimalFormat;
import java.util.ArrayList;

public class MainWindow extends Canvas
{
/** larghezza dello schermo */
public final static int LARGHEZZA = 800;
/** altezza dello schermo */
public final static int ALTEZZA = 600;
/** numero di stelle dello sfondo */
public final static int STELLE = 50;
/** double buffering */
Image doublebuffer;
/** Lista entità sfera */
Ball ball;
/** Lista entità stelle */
Space space[] = null;
//Space space;

/**
* Costruisce il frame ed il pannello su cui andremo a disegnare.
*/
public MainWindow()
{
// crea un frame che conterrà il nostro gioco
JFrame container = new JFrame("TEST");

// aggiunge il pannello al frame e ne imposta le dimensioni
JPanel panel = (JPanel) container.getContentPane();
panel.setPreferredSize(new Dimension(LARGHEZZA,ALTEZZA));
panel.setLayout(null);

// imposta la dimensione del canvas e lo inserisce nel pannello
setBounds(0,0,LARGHEZZA,ALTEZZA);
panel.add(this);

// evita il repainting da parte di AWT
setIgnoreRepaint(true);

// imposta il frame come visibile e non ridimensionabile
container.pack();
container.setResizable(false);
container.setVisible(true);

// aggiunge l'operazione in caso di chiusura del frame
container.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );

// imposta il focus sul frame
requestFocus();
}

/** Inizializza gli elementi */
public void init()
{
// posiziona una stella nel punto selezionato
for (int i = 0; i < STELLE; i++)
space[i] = new Space(i * 2, i * 2);
//space = new Space(getWidth()/3, getHeight()/3);

// posiziona una palla al centro dello schermo e impostane la dimensione
ball = new Ball(getWidth()/2, getHeight()/2);
ball.setRadius(20);

// crea un double buffer della dimensione dello schermo
doublebuffer = createImage(getWidth(),getHeight());
}

/** Loop principale del gioco */
public void gameLoop()
{
// richiama l'inizializzazione degli elementi
init();

// ciclo infinito, DA MODIFICARE
int a = 1;
while (a == 1)
{
// muovi la stella verso il basso
// campo di azione: tutto lo schermo
for (int i = 0; i < STELLE; i++)
space[i].move(ALTEZZA);
//space.move(ALTEZZA);

// muovi la palla verso il basso a destra
// campo di azione: tutto lo schermo
ball.move(1, 1, LARGHEZZA, ALTEZZA);

// richiama il metodo update
repaint();

// imposta la pausa del thread a 60 fps massimi
try { Thread.sleep( 1000 / 60 );
} catch ( Exception e ){}
}
}

/** Metodo update, generalmente resetta gli oggetti a schermo e
* richiama la funzione paint, è stato riscritto per chiamare
* solo la funzione paint */
public void update ( Graphics screen )
{
paint(screen);
}

/** Metodo paint, colora lo sfondo di nero, colora la stella
* e la palla */
public void paint( Graphics screen )
{
// seleziona il double buffer
Graphics g = doublebuffer.getGraphics();

// colora lo sfondo della canvas di nero
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());

// disegna la stella
for (int i = 0; i < STELLE; i++)
space[i].draw(g);
//space.draw(g);

// disegna la palla
ball.draw(g);

//double buffer
screen.drawImage(doublebuffer,0,0,this);

// libera le risorse
g.dispose();
}

/** funzione main, esegue il loop principale */
public static void main(String argv[])
{
MainWindow game = new MainWindow();
game.gameLoop();
}
}

Entity.java
contiene la classe padre da cui derivano i vari elementi
package Space;

import java.awt.Graphics;

public class Entity
{
/** Posizione x corrente dell'entità */
protected int x;
/** Posizione y corrente dell'entità */
protected int y;
/** Velocità corrente dell'entità Orizzontale e Verticale */
protected double dx = 3;
protected double dy = 3;
/** Dimensione entità */
protected int radius;

/** Costruttore dell'entità
* @ x: posizione orizzontale
* @ y: posizione verticale */
public Entity(int x,int y)
{
this.x = x;
this.y = y;
}

/** Restituisce la posizione x dell'entità */
public int getX()
{
return (int) x;
}

/** Restituisce la posizione y dell'entità */
public int getY()
{
return (int) y;
}

/** Imposta la dimensione dell'entità
* @ i: valore dimensione */
public void setRadius(int i)
{
this.radius = i;
}

/** Muove l'entità e controlla il rimbalzamento ai bordi
* @ dirX: direzione orizzontale (1: destra, -1: sinistra)
* può essere usato anche per incrementare la velocità
* di movimento
* @ dirY: direzione verticale (1: giù, -1: su)
* può essere usato anche per incrementare la velocità
* di movimento
* @ larghezza: dimensione orizzontale su cui calcolare il rimbalzo
* @ altezza: dimensione verticale su cui calcolare il rimbalzo */
public void move(int dirX, int dirY, int larghezza, int altezza)
{
// imposta direzione di movimento
x += dirX * dx;
y += dirY * dy;

// calcola il rimbalzo sui muri laterali
if (this.x < 0 || this.x > larghezza - radius)
dx = -dx;

// calcola il rimbalzo sui muri superiore ed inferiore
if (this.y < 0 || this.y > altezza - radius)
dy = -dy;
}
}

Ball.java
figlio di entity, implementa una sfera gialla con movimento obliquo che rimbalza sui bordi del frame
package Space;

import java.awt.Graphics;
import java.awt.Color;

/** Implementa una sfera che si muove */

public class Ball extends Entity
{
/** Costruttore dell'entità
* @ x: posizione orizzontale
* @ y: posizione verticale */
public Ball(int x,int y)
{
super(x, y);
}

/** Disegna l'entità */
public void draw(Graphics g)
{
// variabili locali di posizione
int posX, posY;

// imposta la posizione dell'entità
posX = this.x;
posY = this.y;

// colorala
g.setColor(Color.YELLOW);
g.fillOval(posX, posY, radius, radius);
}
}

Space.java
implementa un quadrato che si muove dal punto di creazione verso il basso, una volta raggiunto il bordo inferiore ricomincia dall'alto
(creandone molte in modo random volevo implementare una sorda di background animato di un cielo stellato)
package Space;

import java.awt.Graphics;
import java.awt.Color;

/** Implementa un quadrato che si muove */

public class Space extends Entity
{
/** Velocità corrente dell'entità Verticale */
protected static final double dy = 2;
/** Dimensione entità */
protected static final int radius = 2;

/** Costruttore */
public Space(int x, int y)
{
super(x, y);
}

/** Muovi l'entità verso il basso
* @ altezza: punto in cui viene reinizializzata l'entità
* sul bordo superiore */
public void move(int altezza)
{
this.y += dy;

if (this.y > altezza)
this.y = 0;
}

/** Disegna l'entità */
public void draw(Graphics g)
{
// variabili locali di posizione
int posX, posY;

// imposta la posizione dell'entità
posX = this.x;
posY = this.y;

// colorala
g.setColor(Color.WHITE);
g.fillRect(posX, posY, radius, radius);
}
}

banryu79
16-09-2008, 13:58
Banryu ho provato a fare come dici tu ma sebbene compili correttamente continua a segnalarmi l'errore: NullPointerException... [cut]

Sì scusami, facendo puntare l'array a null per forza... me misero :cry:
Perdonami, devi inizializzare il tuo array di Space così, per esempio:

Space space[] = new Space[50]; //alloca un array con dimensione pari a 50 elementi di tipo Space


Comunque considera che puoi usare le Collection invece degli array.

ArrayList<Space> spaceList = new ArrayList<Space>();

aggiungi elementi con:

Space aSpace = new Space(x,y);
spaceList.add(aSpace);

//equivalente
spaceList.add(new Space(x,y));


itera

Iterator<Space> itSpace = spaceList.iterator();
while(itSpace.hasNext())
{
Space aSpace = itSpace.next();
}

o col cliclo for

void methodDoSomenthing(Collection<Space> c)
{
for(Space s : c)
{
s.doSomenthing();
}
}

Donbabbeo
16-09-2008, 14:21
grazie!!!!

Finalmente funziona, ho seguito il tuo consiglio ed ho usato l'arraylist, ho un cielo stellato fantastico ora :D

Se a qualcuno interessasse:

package Space;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.lang.*;
import java.awt.*;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;

public class MainWindow extends Canvas
{
/** larghezza dello schermo */
public final static int LARGHEZZA = 800;
/** altezza dello schermo */
public final static int ALTEZZA = 600;
/** numero di stelle dello sfondo */
public final static int STELLE = 200;
/** double buffering */
Image doublebuffer;
/** Lista entità sfera */
Ball ball;
/** Lista entità stelle */
ArrayList<Space> spaceList = new ArrayList<Space>();
//Space space;

/**
* Costruisce il frame ed il pannello su cui andremo a disegnare.
*/
public MainWindow()
{
// crea un frame che conterrà il nostro gioco
JFrame container = new JFrame("TEST");

// aggiunge il pannello al frame e ne imposta le dimensioni
JPanel panel = (JPanel) container.getContentPane();
panel.setPreferredSize(new Dimension(LARGHEZZA,ALTEZZA));
panel.setLayout(null);

// imposta la dimensione del canvas e lo inserisce nel pannello
setBounds(0,0,LARGHEZZA,ALTEZZA);
panel.add(this);

// evita il repainting da parte di AWT
setIgnoreRepaint(true);

// imposta il frame come visibile e non ridimensionabile
container.pack();
container.setResizable(false);
container.setVisible(true);

// aggiunge l'operazione in caso di chiusura del frame
container.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );

// imposta il focus sul frame
requestFocus();
}

/** Inizializza gli elementi */
public void init()
{
// posiziona una stella nel punto selezionato
for (int i = 0; i < STELLE; i++)
{
spaceList.add(new Space((int)(Math.random() * LARGHEZZA), (int)(Math.random() * ALTEZZA)));
}
//space = new Space(getWidth()/3, getHeight()/3);

// posiziona una palla al centro dello schermo e impostane la dimensione
ball = new Ball(getWidth()/2, getHeight()/2);
ball.setRadius(20);

// crea un double buffer della dimensione dello schermo
doublebuffer = createImage(getWidth(),getHeight());
}

/** Loop principale del gioco */
public void gameLoop()
{
// richiama l'inizializzazione degli elementi
init();

// ciclo infinito, DA MODIFICARE
int a = 1;
while (a == 1)
{
// muovi la stella verso il basso
// campo di azione: tutto lo schermo
Iterator<Space> itSpace = spaceList.iterator();
while(itSpace.hasNext())
{
Space element = itSpace.next();
element.move(ALTEZZA);
}
//space.move(ALTEZZA);

// muovi la palla verso il basso a destra
// campo di azione: tutto lo schermo
ball.move(1, 1, LARGHEZZA, ALTEZZA);

// richiama il metodo update
repaint();

// imposta la pausa del thread a 60 fps massimi
try { Thread.sleep( 1000 / 60 );
} catch ( Exception e ){}
}
}

/** Metodo update, generalmente resetta gli oggetti a schermo e
* richiama la funzione paint, è stato riscritto per chiamare
* solo la funzione paint */
public void update ( Graphics screen )
{
paint(screen);
}

/** Metodo paint, colora lo sfondo di nero, colora la stella
* e la palla */
public void paint( Graphics screen )
{
// seleziona il double buffer
Graphics g = doublebuffer.getGraphics();

// colora lo sfondo della canvas di nero
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());

// disegna la stella
Iterator<Space> itSpace = spaceList.iterator();
while(itSpace.hasNext())
{
Space element = itSpace.next();
element.draw(g);
}
//space.draw(g);

// disegna la palla
ball.draw(g);

//double buffer
screen.drawImage(doublebuffer,0,0,this);

// libera le risorse
g.dispose();
}

/** funzione main, esegue il loop principale */
public static void main(String argv[])
{
MainWindow game = new MainWindow();
game.gameLoop();
}
}

banryu79
16-09-2008, 14:48
Scusa la curiosità ma:

public MainWindow()
{
// crea un frame che conterrà il nostro gioco
JFrame container = new JFrame("TEST");

// aggiunge il pannello al frame e ne imposta le dimensioni
JPanel panel = (JPanel) container.getContentPane();
panel.setPreferredSize(new Dimension(LARGHEZZA,ALTEZZA));
panel.setLayout(null);

// imposta la dimensione del canvas e lo inserisce nel pannello
setBounds(0,0,LARGHEZZA,ALTEZZA);
panel.add(this);

// evita il repainting da parte di AWT
setIgnoreRepaint(true);


considerando che la tua Window non è full-screen non hai nessun side-effect a fare quella chiamata (in grassetto)?
Ho visto che ci pensi tu a chiamare un "repaint()" della Window circa ogni "Thread.sleep( 1000 / 60 )" ma se ridimensiono al volo la finestra del gioco oppure ci sovvrappongo parzialmente un'altra finestra di un'altra applicazione aperta, va tutto bene?
Lo chiedo per curiosità, leggendo le Javadoc su setIgnoreRepaint mi ero fatto una prima idea, forse parziale, della questione:
(quotazione dalla javadoc Sun del JDK 1.6)

setIgnoreRepaint

public void setIgnoreRepaint(boolean ignoreRepaint)

Sets whether or not paint messages received from the operating system should be ignored. This does not affect paint events generated in software by the AWT, unless they are an immediate response to an OS-level paint message.

This is useful, for example, if running under full-screen mode and better performance is desired, or if page-flipping is used as the buffer strategy.

Since:
1.4
See Also:
getIgnoreRepaint(), Canvas.createBufferStrategy(int), Window.createBufferStrategy(int), BufferStrategy, GraphicsDevice.setFullScreenWindow(java.awt.Window)


P.S.:
Visto che ti piace cimentarti con Java2D ti linko questo thread (http://www.hwupgrade.it/forum/showthread.php?t=1817420) dove potresti trovare altri stimoli, ciao :)

Donbabbeo
16-09-2008, 15:01
Il link che hai postato l'avevo già letto tempo addietro, purtroppo ciò che sto facendo non è solo per passione, ho l'obbligo di usare solo librerie standard... :D

RETTIFICA SULL'IGNORE REPAINT:

Ho appena aggiunto un'ulteriore classe figlia di Entity che invece di essere disegnata a schermo è formata da un'immagine. In questo caso senza il comando ignoreRepaint vengono fuori i seguenti messaggi di errore (sebbene si compili e continui ad eseguirsi senza alcun errore):

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Space.MainWindow.paint(MainWindow.java:141)
at sun.awt.RepaintArea.paintComponent(RepaintArea.java:248)
at sun.awt.RepaintArea.paint(RepaintArea.java:224)
at sun.awt.windows.WComponentPeer.handleEvent(WComponentPeer.java:301)
at java.awt.Component.dispatchEventImpl(Component.java:4489)
at java.awt.Component.dispatchEvent(Component.java:4243)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)

banryu79
16-09-2008, 16:42
RETTIFICA SULL'IGNORE REPAINT:

Ho appena aggiunto un'ulteriore classe figlia di Entity che invece di essere disegnata a schermo è formata da un'immagine. In questo caso senza il comando ignoreRepaint vengono fuori i seguenti messaggi di errore (sebbene si compili e continui ad eseguirsi senza alcun errore):

Ehm, sì ok, ma io non intendevo suggerire che tu dovessi toglierlo :stordita: stavo solo chiedendo se con quella chiamata presente non avessi problemi della serie "artefatti grafici" o altre "anomalie" quando sovrapponi e muovi un'altra finestra davanti a quella della tua applicazione che sta girando o provi a ridimensionare la tua finestra mediante trascinamento dei bordi.

La mia era semplice curiosità.

Donbabbeo
16-09-2008, 19:33
ahhhh :asd:

no no a parte qualche warning durante l'esecuzione funziona bene in entrambi i modi :D

banryu79
17-09-2008, 08:21
Ok, grazie.

Donbabbeo
17-09-2008, 13:43
Aggiungo qua che non è il caso di aprire un nuovo topic:

Sto cercando di modificare l'entità in modo che sia possibile caricare sprites al posto di disegnare oggetti. Funziona bene, il problema è che carico ad ogni costruttore della flotta tante immagini quanti sono gli oggetti, mentre io mi accontenterei di caricarlo UNA volta e riutilizzarlo.

Questo è il costruttore della flotta, come si può vedere per ogni entità richiama il caricamento della funzione loadSprite che gli incolla un'immagine.
/** Costruttore della flotta
* @ colonne: numero delle colonne della flotta
* (numero alieni per riga)
* @ righe: numero di righe della flotta */
public Flotta(int righe, int colonne)
{
int indice = 0;

// posizione alcuni alieni in formazione
for (int i = 0; i < righe; i++)
{
for (int j = 0; j < colonne; j++)
{
alienoList.add(new Alieno((40 * j), (25 * i)));
alienoList.get(indice).loadSprite("alien10A");
alienoList.get(indice).setVel(1, 2);
indice++;
}
}
}

Questa è la funzione all'interno dell'entità, come vedete è stata già "pensata" per controllare se esiste già un'immagine caricata con quel nome, solo che manca tutta la parte che lo fa :stordita:
/** Carica l'immagine in base al suo indirizzo
* @ nome: indirizzo completo dell'immagine*/
private BufferedImage loadImmagine(String nome)
{
URL url=null;
try { url = getClass().getClassLoader().getResource(nome);
return ImageIO.read(url);
} catch (Exception e) { System.out.println("Impossibile caricare l'immagine " + nome);
System.exit(0);
return null;}
}

/** Ottiene l'indirizzo completo dell'immagine
* e richiama la funzione di caricamento
* @ nome: nome dell'immagine */
public BufferedImage loadSprite(String nome)
{
immagine = loadImmagine("res/images/" + nome + ".bmp");
return immagine;
}

So che dovrebbe essere fatto dentro loadSprite, precisamente un qualcosa tipo

Controlla se esiste immagine con nome nella struttura, se non esiste richiama la funzione loadImmagine con il nome dell'immagine e aggiungi l'immagine alla struttura.
Il problema è su cosa controllo? Dovrei creare un arraylist di immagini? Un array di stringhe e uno di immagini grandi uguali?
Consigli?

banryu79
17-09-2008, 16:20
Potresti usare una HashMap, e mappare le coppie: nomefileImmagine(come chiave) - bufferedImage(come valore).

Quando devi caricare una nuova immagine prima controlli se quel nomeFileImmagine è già presente nella HashMap, e in quel caso passi il relativo reference, oppure se devi proprio caricarlo, e in quel caso poi lo inserisci nella HashMap.

@EDIT:
visto che ti stai tuffando nelle bellezze della grafica 2D con uso di immagini in ambito Java2D, ti segnalo questa pagina (http://weblogs.java.net/mt/search?IncludeBlogs=81&search=BufferedImage+as+good+as+butter) che contiene tre link ad altrettanti articoli presenti nel blog di Chet Haase; leggili (quando avrai tempo per farlo con calma), ti assicuro che non te ne pentirai :D

Donbabbeo
17-09-2008, 20:16
Indovina un pò? ho bisogno di un aiutino :D

Ho implementato un'intera nuova classe che carica le sprite:

package Space;

/** Inclusione librerie */
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.net.URL;
import javax.imageio.ImageIO;

/** Classe che raccoglie tutti gli sprites */
public class SpriteCache
{
// variabili locali
private HashMap sprites;

/** Costruttore */
public SpriteCache()
{
sprites = new HashMap();
}

/** Carica l'immagine in base al suo indirizzo
* @ nome: indirizzo completo dell'immagine*/
private BufferedImage loadImmagine(String nome)
{
URL url=null;
try { url = getClass().getClassLoader().getResource(nome);
return ImageIO.read(url);
} catch (Exception e) { System.out.println("Impossibile caricare l'immagine " + nome);
System.exit(0);
return null;}
}

/** Ottiene l'indirizzo completo dell'immagine
* e richiama la funzione di caricamento
* @ nome: nome dell'immagine */
public BufferedImage loadSprite(String nome)
{
BufferedImage immagine = (BufferedImage)sprites.get(nome);
if (immagine == null)
{
immagine = loadImmagine("res/images/" + nome + ".bmp");
sprites.put(nome, immagine);
}
return immagine;
}
}

Carica l'immagine, la mette nell'HashMap e ogni volta che viene richiamata, controlla che non sia già presente.
Il problema viene quando cerco di utilizzare questa classe...

Nella classe padre Entità ho aggiunto 2 variabili

protected String spriteName;

protected SpriteCache spriteCache;

e 2 funzioni che impostano il nome dell'entità e lo restituiscono
/** Imposta il nome della sprite */
public void setSpriteName(String nome)
{
spriteName = nome;
BufferedImage immagine = spriteCache.getSprite(spriteName);
}

/** Restituisce il nome della sprite usata dall'entità */
public String getSpriteName()
{
return spriteName;
}

A questo punto ho modificato anche il costruttore delle varie classi figlie, per cui al momento della creazione, viene caricata automaticamente l'immagine

public class Astronave extends Entità
{
/** Costruttore dell'entità
* @ x: posizione orizzontale
* @ y: posizione verticale */
public Astronave(int x,int y)
{
super(x, y);
setSpriteName("laserX");
}//Eccetera eccetera...

// disegna l'entità
g.drawImage(spriteCache.getSprite(spriteName), posX, posY, null);


A questo punto quando nella main richiamo l'aggiunta di un nuovo elemento agli arrayList di entità, l'oggetto è già inizializzato, senza alcun bisogno di impostare nulla, se non il disegno.
Sulla carta direi che è corretto e anche sensato, peccato che non lo sia nella pratica visto che mi dice che SpriteCache non esiste bla bla bla:

C:\Users\Josh\Desktop\MainWindow\src\Entità.java:25: cannot find symbol
symbol : class SpriteCache
location: class Space.Entità
protected SpriteCache spriteCache;
^
C:\Users\Josh\Desktop\MainWindow\src\MainWindow.java:41: cannot find symbol
symbol : class SpriteCache
location: class Space.MainWindow
SpriteCache spriteCache;
^
C:\Users\Josh\Desktop\MainWindow\src\MainWindow.java:77: cannot find symbol
symbol : class SpriteCache
location: class Space.MainWindow
spriteCache = new SpriteCache();
^
Note: C:\Users\Josh\Desktop\MainWindow\src\SpriteCache.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
3 errors

Process completed.


eppure lo inizializzo lo spritecache, sia nell'entità che nella main, (come si può vedere dai messaggi di errore). Soluzioni?

banryu79
18-09-2008, 08:56
nei vari file .java dove hai definito la classe Entità e le altre classi che la estendono hai fatto l'import di Space.SpriteCache?

Perchè se hai definito la classe SpiteCache in un suo package diverso da quello dove sono definite Entità e le sue sottoclassi, allora devi fare l'import.

Donbabbeo
18-09-2008, 10:01
:doh: Ste cose le lascio fare all'editor ma a volte è meglio farle a mano :mbe:
Com'è logico il problema era quello, facendo build project l'editor non mi caricava la class di SpriteCache :muro:

Caricando ciascun file a mano ora funziona perfettamente!!!

E' normale che usando SpriteCache mi segnali questo?

Note: C:\Users\Josh\Desktop\MainWindow\src\SpriteCache.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

Process completed.

banryu79
18-09-2008, 10:35
E' normale che usando SpriteCache mi segnali questo?

Note: C:\Users\Josh\Desktop\MainWindow\src\SpriteCache.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

Process completed.

Se vuoi scoprire cosa significa ricompila passando come opzione di compilazione il parametro -Xlint.
Avrai un output di compilazione più "verboso" che ti informerà in dettaglio della faccenda (comunque niente di grave, si tratta di warning).

Altrimenti, se non hai pazienza leggi lo spoiler :D

Quel messaggio appare quando usi classi che supportano la feature dei Generics, presente dalla versione 1.5 di Java. Saltano fuori ogni volta che usai una collection senza specificare il tipo parametrico che dovrà contenere.
Per sempio, nel tuo caso stai usando una HashMap per mappare il nome di una immagine e l'immagine corrispondente ma l'hia dichiarata e usata come una HashMap generica:
HashMap sprites;
Potevi anche dichiararla e usarla come una HashMap tipizzata:
HashMap<String,BufferedImage> sprites;

Donbabbeo
18-09-2008, 11:40
oleee niente più warning :D

Ho implementato l'animazione di ogni sprite, ora il costruttore della flotta di alieni richiama una riga per tipo esattamente come in space invaders originale.

Il prossimo passo è inserire il keylistener per muovere l'astronave e implementare il laser, poi le collisioni e dopo ho fatto :D

PS: se passo a padova ti pago una cena :asd:


PSS: stavo pensando alla situazione del laser e delle collisioni con gli alieni: per le collisioni con l'astronave non c'è problema, faccio che se l'ultimo elemento della flotta (che è ovviamente quello più in basso in ogni caso) arriva all'altezza a cui ho posizionato l'astronave perdiamo e bona, per le collisioni tra laser e alieni non c'è problema, rimuovo direttamente l'alieno che collide, mentre per il laser? Il laser è un'entità singola (posso avere un solo raggio in gioco per volta), quindi non ho una lista da cui rimuoverlo, lo setto semplicemente come "invisibile" e lo metto in un punto qualsiasi, poi al momento dello sparo lo metto nella stessa posizione x e y dell'astronave e ne avvio il movimento? Mmm mi son risposto da solo mi sa :asd:

Donbabbeo
18-09-2008, 11:52
AHHHH mi ero dimenticato una cosa: in entità ho un sacco di funzioni che richiedono di sapere la dimensione dello schermo... Come faccio ad ottenere tale valore? per ora glielo passo come parametro delle varie funzioni ma è poco elegante, vorrei cambiare la costante nel main e automaticamente vedere variare tutte le funzioni...

qualcosa tipo getWidth(), solo che valga anche fuori dalla funzione principale...

banryu79
18-09-2008, 13:20
AHHHH mi ero dimenticato una cosa: in entità ho un sacco di funzioni che richiedono di sapere la dimensione dello schermo... Come faccio ad ottenere tale valore? per ora glielo passo come parametro delle varie funzioni ma è poco elegante, vorrei cambiare la costante nel main e automaticamente vedere variare tutte le funzioni...

qualcosa tipo getWidth(), solo che valga anche fuori dalla funzione principale...
Toolkit localTK = Toolkit.getDefaultToolkit();
Dimension screenSize = localTK.getScreenSize();

il tutto gentilmente concesso dal package java.awt

Donbabbeo
18-09-2008, 16:19
Aggiunto tutti i listener possibili, posso controllare l'astronave e sparare sia tramite tastiera che mouse :D

Se carico l'applicazione ed il mouse si trova al suo interno saltano fuori alcuni messaggi di errore, soluzione? Rimuovere il mousemovelistener? :asd:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Space.MainWindow.mouseMoved(MainWindow.java:255)
at java.awt.Component.processMouseMotionEvent(Component.java:6086)
at java.awt.Component.processEvent(Component.java:5810)
at java.awt.Component.dispatchEventImpl(Component.java:4413)
at java.awt.Component.dispatchEvent(Component.java:4243)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)

banryu79
18-09-2008, 16:23
Puoi postare il messaggio di output completo? In quello che hai appena postato si vede dove viene generata l'eccezione ma non quale eccezione è stata lanciata :confused:

Donbabbeo
18-09-2008, 19:39
Ops, errore mio.
Aggiunto la riga che mancava.
Il problema dipende comunque dal MouseMotion quando il puntatore è all'interno del frame, se non lo uso nessun warning.

banryu79
19-09-2008, 07:57
Bene, facciamo un altro passo in avanti: prova un po' a postare il codice del metodo mouseMoved() della tua classe MainWindow...
(bisogna tirarti fuori le cose con le tenaglie a quanto pare :D )

Donbabbeo
19-09-2008, 09:22
Bene, facciamo un altro passo in avanti: prova un po' a postare il codice del metodo mouseMoved() della tua classe MainWindow...
(bisogna tirarti fuori le cose con le tenaglie a quanto pare :D )

:asd:

Ecco qua:

/** Azione eseguita in caso di movimento del mouse */
public void mouseMoved(MouseEvent me)
{
// Leggi la posizione del puntatore
posX = me.getX();
// Muovi l'astronave di conseguenza
astronave.muoviMouse(posX);
}

/** Azione eseguita in caso di trascinamento del mouse */
public void mouseDragged(MouseEvent me)
{
mouseMoved(me);
}

La funzione richiamata fa semplicemente questo:

public void muoviMouse(int val)
{
this.setX(val);
}

Intanto finisco di implementare le collisioni :D

banryu79
19-09-2008, 11:10
Humm, prova ad aggiungere queste due righe al tuo codice, a scopo "investigativo":

/** Azione eseguita in caso di movimento del mouse */
public void mouseMoved(MouseEvent me)
{
if (me == null)
{
System.out.println("in mouseMoved():");
System.out.println("received mouse Event is Null!");
}
// Leggi la posizione del puntatore
posX = me.getX();
// Muovi l'astronave di conseguenza
astronave.muoviMouse(posX);
}

/** Azione eseguita in caso di trascinamento del mouse */
public void mouseDragged(MouseEvent me)
{
if (me == null)
{
System.out.println("in mouseDragged():");
System.out.println("received mouse Event is Null!");
}
mouseMoved(me);
}

Quindi manda in esecuzione la tua applicazione e genera eventi col mouse. Guarda l'output e prova a postare i risultati.
Voglio essere sicuro che il null pointer sia il mouseEvent, e voglio capire in quale caso succede, ho una mezza idea ma forse è una fesseria.

Donbabbeo
19-09-2008, 14:46
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Space.MainWindow.mouseMoved(MainWindow.java:273)
at java.awt.Component.processMouseMotionEvent(Component.java:6086)
at java.awt.Component.processEvent(Component.java:5810)
at java.awt.Component.dispatchEventImpl(Component.java:4413)
at java.awt.Component.dispatchEvent(Component.java:4243)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)

Immagino che tu pensassi al fatto che all'avvio dell'applicazione non inizializzo a null il mouseEvent? C'hai ragione :asd:

Sto dando un'occhiata per il web ma non c'è molto a riguardo...

banryu79
19-09-2008, 14:56
Immagino che tu pensassi al fatto che all'avvio dell'applicazione non inizializzo a null il mouseEvent? C'hai ragione :asd:

Questo non l'ho capito.

Ma hai provato a modificare il codice come ti ho suggerito e il risultato dell'output è quello che hai postato?
Se non erro mi pare di sì (dai numeri di riga nell'output dell'eccezione si capisce che rispetto al primo post il numero di riga è diverso perchè probabilmente hai aggiunto del codice che prima non c'era).

Se per te non è un problema, potresti postare l'intera classe MainWindow?

Donbabbeo
19-09-2008, 16:07
Ma non c'è bisogno che ci perdi così tanto tempo eh! Dà errore? La tolgo direttamente visto che ho altri sistemi di controllo, non preoccuparti :D

package Space;

/** Inclusione librerie */
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Image;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Dimension;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

/** Funzione principale, si preoccupa di caricare la finestra,
* muovere gli oggetti e disegnare. */
public class MainWindow extends Canvas implements KeyListener, MouseListener, MouseMotionListener
{
/** larghezza dello schermo */
public final static int LARGHEZZA = 800;
/** altezza dello schermo */
public final static int ALTEZZA = 600;
/** numero di stelle dello sfondo */
public final static int STELLE = 200;
/** numero di alieni per riga */
public final static int COLONNE = 12;
/** numero di righe di alieni */
public final static int RIGHE = 5;
/** double buffering */
Image doublebuffer;
/** Entità cielo */
Cielo cielo;
/** Entità flotta */
Flotta flotta;
/** Entità astronave */
Astronave astronave;
/** Entità laser del giocatore */
Laser laserUser;
/** variabile Highscore */
int highscore;
/** variabile punteggio */
int punteggio;
/** variabile vite */
int vite;
/** posizione orizzontale dell'astronave */
int posX;
/** avverte se il gioco è in esecuzione */
boolean gameRunning = false;
/** avverte se è avvenuta una collisione */
boolean collisione = false;

/**
* Costruisce il frame ed il pannello su cui andremo a disegnare.
*/
public MainWindow()
{
// crea un frame che conterrà il nostro gioco
JFrame container = new JFrame("TEST");

// aggiunge il pannello al frame e ne imposta le dimensioni
JPanel panel = (JPanel) container.getContentPane();
panel.setPreferredSize(new Dimension(LARGHEZZA,ALTEZZA));
panel.setLayout(null);

// imposta la dimensione del canvas e lo inserisce nel pannello
setBounds(0,0,LARGHEZZA,ALTEZZA);
panel.add(this);

// evita il repainting da parte di AWT
setIgnoreRepaint(true);

// imposta il frame come visibile e non ridimensionabile
container.pack();
container.setResizable(false);
container.setVisible(true);

// aggiunge l'operazione in caso di chiusura del frame
container.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );

// imposta il focus sul frame
requestFocus();

// aggiunge i keylistener
addKeyListener(this);
addMouseMotionListener(this);
addMouseListener(this);
}

/** Inizializza gli elementi */
public void init()
{
// inizializza il punteggio e le vite
punteggio = 0;
vite = 3;

// posizione iniziale dell'astronave
posX = getWidth()/2;

// inizializza il cielo stellato
cielo = new Cielo(STELLE, LARGHEZZA, ALTEZZA);

// inizializza l'astronave
astronave = new Astronave(posX, getHeight() - 40);

// inizializza il laser del giocatore
laserUser = new Laser();

// inizializza la flotta
flotta = new Flotta(RIGHE, COLONNE);

// crea un double buffer della dimensione dello schermo
doublebuffer = createImage(getWidth(),getHeight());
}

/** Loop principale del gioco */
public void gameLoop()
{
// inizializzazione degli elementi di gioco
init();
// imposta il gioco in esecuzione RIMUOVERE
gameRunning = true;

// loop principale
while (gameRunning == true)
{
// muovi le stelle
// campo di azione: schermo verticale
cielo.muovi(ALTEZZA);

// muovi il laser del giocatore se in gioco
// controllane le collisioni con la flotta
// se il punteggio aumenta significa che c'è stata
// collisione, quindi rimuove il laser
if (laserUser.isLive() == true)
{
int prima = punteggio;
laserUser.spara(-1);
punteggio += flotta.checkColl(laserUser);
if (punteggio > prima)
laserUser.distruggi();
}

// muovi la flotta
// campo di azione: tutto lo schermo
flotta.muovi(LARGHEZZA);

// controlla highscore
if(punteggio >= highscore)
highscore = punteggio;

// richiama il metodo update
repaint();

// imposta la pausa del thread
try { Thread.sleep(1000/60);
} catch ( Exception e ){}
}
}

/** Metodo update, generalmente resetta gli oggetti a schermo e
* richiama la funzione paint, è stato riscritto per chiamare
* solo la funzione paint */
public void update ( Graphics screen )
{
paint(screen);
}

/** Metodo paint, colora lo sfondo di nero, colora la stella
* e la palla */
public void paint( Graphics screen )
{
// seleziona il double buffer
Graphics g = doublebuffer.getGraphics();

// colora lo sfondo della canvas di nero
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());

// scrivi informazioni a schermo
g.setColor(Color.WHITE);
Font f = new Font("Courier", Font.BOLD, 18);
g.setFont(f);
g.drawString("Vite " + vite, 20, getHeight() - 10);
g.drawString("Score " + punteggio, 2, 15);
g.drawString("HighScore "+ highscore, getWidth()/2, 15);
f = new Font("Courier", Font.PLAIN, 12);
g.setFont(f);
g.drawString("Versione 1.00a", getWidth()-100, getHeight()-5);

// disegna il cielo stellato
cielo.disegna(g);

// disegna l'astronave
astronave.disegna(g);

// disegna il laser
// se in gioco
if (laserUser.isLive() == true)
laserUser.disegna(g);

// disegna la flotta
flotta.disegna(g);

//double buffer
screen.drawImage(doublebuffer,0,0,this);

// libera le risorse
g.dispose();
}

/** Gestione del personaggio tramite tastiera */
/** Azioni eseguite in caso di pressione di un tasto */
public void keyPressed(KeyEvent e)
{
// Azione eseguite in caso di pressione dello spazio
if (e.getKeyCode() == KeyEvent.VK_SPACE)
{
// Verifica che non ci siano altri laser in gioco e reinizializzalo
if (laserUser.isLive() == false)
laserUser.reset(astronave.getX() + astronave.dimImgX / 2, astronave.getY());
}

// Azione eseguita in caso di pressione del tasto sinistro
if (e.getKeyCode() == KeyEvent.VK_LEFT)
{
// Muovi l'astronave verso sinistra
astronave.muoviTastiera(-4);
}

// Azione eseguita in caso di pressione del tasto destro
if (e.getKeyCode() == KeyEvent.VK_RIGHT)
{
// Muovi l'astronave verso destra
astronave.muoviTastiera(4);
}
}

/** Funzioni obbligatorie in caso di uso di KeyEvent */
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}

/** Gestione personaggio tramite mouse */
/** Azione eseguita in caso di pressione del tasto */
public void mouseClicked(MouseEvent me)
{
// Verifica che non ci siano altri laser in gioco e reinizializzalo
if (laserUser.isLive() == false)
laserUser.reset(astronave.getX() + astronave.dimImgX / 2, astronave.getY());
}

/** Funzioni obbligatorie in caso di uso di MouseEvent */
public void mouseEntered(MouseEvent me) {}
public void mousePressed(MouseEvent me) {}
public void mouseReleased(MouseEvent me) {}
public void mouseExited(MouseEvent me) {}

/** Azione eseguita in caso di movimento del mouse */
public void mouseMoved(MouseEvent me)
{
// Leggi la posizione del puntatore
posX = me.getX();
// Muovi l'astronave di conseguenza
astronave.muoviMouse(posX);
}

/** Azione eseguita in caso di trascinamento del mouse */
public void mouseDragged(MouseEvent me)
{
mouseMoved(me);
}

/** funzione main, esegue il loop principale */
public static void main(String argv[])
{
MainWindow game = new MainWindow();
game.gameLoop();
}
}

(Ho ritolto la parte di codice che mi hai dato)
E' praticamente completo, manca giusto un paio di righe di codice per implementare uno screen di benvenuto, sostituire il numero di vite con delle miniature dell'astronave (fa più figo :asd: ) e implementare una funzione per far sparare gli alieni (questa la vedo più dura, so già come farla ma sembra non funzionare :muro: )

banryu79
19-09-2008, 16:21
Ok ci ho dato una veloce occhiata, francamente non capisco quale possa essere il problema.

Se proprio vuoi evitare il lancio di quella eccezione a runtime allora potresti condizionare l'esecuzione del codice nel metodo mouseMoved() con un if che controlla se il mouse event ricevuto è diverso da null.
Però non mi piace molto come soluzione.


Ma non c'è bisogno che ci perdi così tanto tempo eh!

Lo faccio perchè potrei imparare qualcosa di nuovo che ancora non conosco, come questa faccenda del MouseEvent nullo.

Ultima spiaggia (della serie partorisco la cazzata non sapendo più che pesci pigliare): prova a commentare la riga dove fai la chiamata setIgnoreRepaint() e vedere che succede, non c'entra nulla in teoria, ma voglio togliermi il prurito :D

Donbabbeo
19-09-2008, 18:31
In quel caso raddoppiano le eccezioni, oltre che per il mouseevent ne arrivano altri per il repaint:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Space.MainWindow.mouseMoved(MainWindow.java:174)
at java.awt.Component.processMouseMotionEvent(Component.java:6086)
at java.awt.Component.processEvent(Component.java:5810)
at java.awt.Component.dispatchEventImpl(Component.java:4413)
at java.awt.Component.dispatchEvent(Component.java:4243)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Space.MainWindow.paint(MainWindow.java:260)
at sun.awt.RepaintArea.paintComponent(RepaintArea.java:248)
at sun.awt.RepaintArea.paint(RepaintArea.java:224)
at sun.awt.windows.WComponentPeer.handleEvent(WComponentPeer.java:301)
at java.awt.Component.dispatchEventImpl(Component.java:4489)
at java.awt.Component.dispatchEvent(Component.java:4243)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)

Donbabbeo
20-09-2008, 16:36
Abbiamo fatto progressi, ho aggiunto i suoni ed un welcome screen animato.
Il problema viene quando calcolo la collisione della flotta con l'astronave...

Avevo pensato di ottenere l'ultimo elemento dell'arraylist (che di logica dovrebbe essere il più in basso a destra) e verificare che non collida con l'astronave...

Di conseguenza facevo:
[CODE]int i = NOMEARRAYLIST.size()
NOMEARRAYLIST.get(i).x & NOMEARRAYLIST.get(i).y[CODE]
e li confrontavo con quelli dell'entità... però dà un'eccezione e dice che punta a valore nullo...

Intanto lo posto per vedere se qualcuno sa qualcosa, poi domani farò un'analisi più dettagliata, ora non posso che vado di fretta. A domani :D

Donbabbeo
21-09-2008, 12:06
Abbiamo fatto progressi, ho aggiunto i suoni ed un welcome screen animato.
Il problema viene quando calcolo la collisione della flotta con l'astronave...

Avevo pensato di ottenere l'ultimo elemento dell'arraylist (che di logica dovrebbe essere il più in basso a destra) e verificare che non collida con l'astronave...

Di conseguenza facevo:
[CODE]int i = NOMEARRAYLIST.size()
NOMEARRAYLIST.get(i).x & NOMEARRAYLIST.get(i).y[CODE]
e li confrontavo con quelli dell'entità... però dà un'eccezione e dice che punta a valore nullo...

Intanto lo posto per vedere se qualcuno sa qualcosa, poi domani farò un'analisi più dettagliata, ora non posso che vado di fretta. A domani :D

Risolto :D

Donbabbeo
21-09-2008, 15:07
finito :D

Una volta che sarà terminato l'esame vi lascio tutti i sorgenti :D

banryu79
22-09-2008, 09:38
Sì, beh sta cosa del MouseEvent nullo proprio mi da fastidio, non capisco ne riesco a ipotizzare da cosa dipenda o potrebbe dipendere. A me non è mai capitato fin'ora di avere un simile problema, bho.

In bocca al lupo per l'esame ;)

Donbabbeo
23-09-2008, 13:13
uhm... ho trovato un bug?

In teoria questo comando:

int indice = (int) Math.random() * alienoList.size();

dovrebbe restituirmi l'indice di un qualsiasi alieno della flotta giusto?
Purtroppo restituisce SEMPRE l'indice del primo elemento.

In pratica tale funzione fa parte della istruzione per sparare degli alieni, io in modo random scelgo un alieno della lista e gli impongo di sparare...
Se metto un valore finito avrò l'alieno giusto che spara, ma se metto sta funzione random mi spara sempre il primo...

sono un idiota :doh:
facevo il casting della sola funzione random e non del prodotto...
l'istruzione giusta è:

int indice = (int) (Math.random() * alienoList.size());