Aquarium en 2d, probleme initialisation type java.awt.Graphics

Cornellus1985 Messages postés 22 Date d'inscription dimanche 26 avril 2009 Statut Membre Dernière intervention 7 juillet 2009 - 26 avril 2009 à 20:00
Cornellus1985 Messages postés 22 Date d'inscription dimanche 26 avril 2009 Statut Membre Dernière intervention 7 juillet 2009 - 1 mai 2009 à 11:37
Bonjour,
Je suis en train de developper un petit projet en java SE.
Il s'agit de creer un aquarium en utilisant des java.awt.image.BufferedImage afin de permettre un chargement de l'image en arriere plan avant de l'afficher.
Le projet se constitue de 4 classes, une classe Aquarium, une classe Tank, une classe Main et une classe Fish.
Je me sers de trois images afin de dessiner l'aquarium et les poissons. Ces images au format .gif sont stocker dans un dossier nomme "images" lui-meme place dans le dossier source (src) du projet.
Enfin je developpe sur Mac, avec Netbeans 6.5 et le jdk1.6.

Voici le code de l'application :

LA CLASSE TANK

package aquarium;

import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.MediaTracker;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.Vector;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
/**
*
* @author Cornellus1985
*/
public class Tank extends JPanel implements Runnable {

private MediaTracker tracker;
private BufferedImage aquariumImage, memoryImage;
private Graphics memoryGraphics;
private BufferedImage fishImages[] = new BufferedImage[2];
private Thread thread;
private int numberFish = 12;
private int sleepTime = 110;
private Vector<Fish> fishes = new Vector<Fish>();
private boolean runOK = true;

public Tank() {
tracker = new MediaTracker( this );

fishImages[0] = getImage("/images/bubbles.gif");
tracker.addImage( fishImages[0] , 0 );

fishImages[1] = getImage( "/images/fish2.gif" );
tracker.addImage( fishImages[1] , 0 );

aquariumImage = getImage( "/images/bubbles.gif" );
tracker.addImage( aquariumImage , 0 );

try {
tracker.waitForID(0);
}
catch (Exception e) {
System.out.println(e.getMessage());
}

setSize( aquariumImage.getWidth(this) , aquariumImage.getHeight(this));

if (!GraphicsEnvironment.isHeadless()) {
memoryImage = (BufferedImage) createImage(getSize().width, getSize().height);
}

memoryGraphics = memoryImage.getGraphics();

thread = new Thread( this );
}

public void run() {
Rectangle edges = new Rectangle(0 + getInsets().left , 0 + getInsets().top ,
getSize().width - ( getInsets().left + getInsets().right ),
getSize().height - ( getInsets().top + getInsets().bottom ));

for (int loopIndex = 0 ; loopIndex < numberFish ; loopIndex++) {
fishes.add(new Fish( fishImages[0] , fishImages[1] , edges , this ));
try{
Thread.sleep(20);
}
catch (Exception e){
System.out.println(e.getMessage());
}
}

Fish fish;

while ( runOK ) {
for (int loopIndex = 0 ; loopIndex < numberFish ; loopIndex++) {
fish = (Fish)fishes.elementAt(loopIndex);
fish.swim();
}

try{
Thread.sleep(sleepTime);
}
catch (Exception err){
System.out.println(err.getMessage());
}
repaint();
}
}

@Override
public void paintComponents(Graphics g) {
super.paintComponents(g);
g.drawImage(aquariumImage, 0, 0, this);
/*for (int i = 0 ; i < fishImages.length ; i++) {
g.drawImage(fishImages[i] , i + 20 , i + 20 , this);
}*/
}

@Override
public void update(Graphics g) {
if (memoryGraphics != null) {
memoryGraphics.drawImage( aquariumImage , 0 , 0 , this );
}

for ( int loopIndex = 0 ; loopIndex < numberFish ; loopIndex++ ) {
(( Fish )fishes.elementAt( loopIndex )).drawFishImage( memoryGraphics );
}

if (memoryImage != null) {
g.drawImage( memoryImage , 0 , 0 , this );
}
}

public ImageIcon createImageIcon ( String path ){
java.net.URL url = aquarium.Tank.class.getResource(path);

if ( url != null ) {
return new ImageIcon(path);
}
else{
System.out.println("Couldn't find file : " + path);
return null;
}
}

public void setOKRun (boolean value){
this.runOK = value;
}

public void start() {
thread.start();
}

protected BufferedImage getImage(String path) {
URL url = getClass().getResource(path);
BufferedImage img = null;

try {
img = ImageIO.read(url);
}
catch (IOException err) {
System.out.println("read error : " + err.getMessage());
}

return img;
}

}

LA CLASSE AQUARIUM

package aquarium;

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
/**
*
* @author Cornellus1985
*/
public class Aquarium extends Frame{

private Tank aquarium;

public Aquarium() {
setTitle( "Aquarium" );
aquarium = new Tank();
aquarium.start();
setSize( aquarium.getWidth() , aquarium.getHeight() + 20 );
setResizable(false);
add(aquarium);

this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
aquarium.setOKRun(false);
System.exit(0);
}
});
setVisible(true);
}
}

LA CLASSE FISH

package aquarium;

import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JComponent;

/**
*
* @author Cornellus1985
*/
public class Fish {

private Component tank;
private BufferedImage image1, image2;
private Point location, velocity;
private Rectangle edges;
private Random random;

public Fish(BufferedImage image1, BufferedImage image2, Rectangle edges, JComponent tank) {
random = new Random(System.currentTimeMillis());
this.image1 = image1;
this.image2 = image2;
this.edges = edges;
this.tank = tank;
this.location = new Point(100 + (Math.abs(random.nextInt()) % 300), 100 + (Math.abs(100 + random.nextInt()) % 300));
this.velocity = new Point(random.nextInt() % 8, random.nextInt() % 8);
}

public void swim() {
if (random.nextInt() % 7 <= 1) {
velocity.x += random.nextInt() % 4;
velocity.x = Math.min( velocity.x , 8 );
velocity.x = Math.max( velocity.x , -8 );

velocity.y += random.nextInt() % 4;
velocity.y = Math.min( velocity.y , 8 );
velocity.y = Math.max( velocity.y, -8 );
}

if ( location.x < edges.x ) {
location.x = edges.x;
velocity.x = -velocity.x;
}

if ((location.x + image1.getWidth(tank)) > (edges.x + edges.width)) {
location.x = edges.x + edges.width - image1.getWidth(tank);
velocity.x = -velocity.x;
}

if (location.y < edges.y) {
location.y = edges.y;
velocity.y = -velocity.y;
}

if ((location.y + image1.getHeight(tank)) > (edges.y + edges.height)) {
location.y = edges.y + edges.height - image1.getHeight(tank);
velocity.y = -velocity.y;
}
}

public void drawFishImage(Graphics g){
if (velocity.x < 0) {
g.drawImage( image1 , location.x , location.y , tank );
}
else {
g.drawImage( image2 , location.x , location.y , tank );
}
}

}

LA CLASSE MAIN

package aquarium;

/**
*
* @author Cornellus1985
*/
public class Main {

/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Aquarium aquarium = new Aquarium();
}

}

L'erreur survenue a ete marque en gras.
Voici l'erreur survenue :

Exception in thread "main" java.lang.NullPointerException
at aquarium.Tank.(Tank.java:60)
at aquarium.Aquarium.(Aquarium.java:21)
at aquarium.Main.main(Main.java:18)
Java Result: 1

Je pense qu'il s'agit d'une erreur d'initialisation de l'attribut "memoryGraphics" de la classe Tank. Je ne sais pas comment remedier a ce probleme. Dois je surcharger ou surdefinir toutes les methodes de la classe abstraite Graphics ?
Toute aide sera la bienvenue, n'aidez pas a me poser vos questions si certains points restent obscures.

5 réponses

Cornellus1985 Messages postés 22 Date d'inscription dimanche 26 avril 2009 Statut Membre Dernière intervention 7 juillet 2009
27 avril 2009 à 18:25
L'erreur se situe a cette ligne dans la classe Tank :

memoryGraphics = memoryImage.getGraphics();

Il se trouve que l'attribut memoryImage en mode debugg ne s'initialise pas correctement.
Il en resulte une erreur d'initialisation (NullPointerException).

Je voudrais savoir comment recuperer dans une variable de type java.awt.Graphics une ou plusieurs Images du type BufferedImage ??
Le but est de modeliser en arriere plan toutes les images avant d'afficher le resultat pour empecher le "flickering".
Merci d'avance pour votre aide.
A+
0
Twinuts Messages postés 5375 Date d'inscription dimanche 4 mai 2003 Statut Modérateur Dernière intervention 14 juin 2023 111
29 avril 2009 à 12:47
Salut,

si tu utilises createImage il faut que isHeadless soit faux et que isDisplayable soit vrai
et pour avoir isDisplayable à vrai il faut en gros que le panel soit affiché à l'écran...
la comme ça je vois bien 2 solutions :
1 - tu attends que isDisplayable soit vrai...
2 - tu remplaces simplement la ligne :
memoryImage = (BufferedImage) createImage(getSize().width, getSize().height);
par la ligne :
memoryImage = new BufferedImage(getSize().width, getSize().height, BufferedImage.TYPE_INT_ARGB);// le type en fonction de tes besoins

------------------------------------
"On n'est pas au resto : ici on ne fait pas dans les plats tout cuits ..."

OoWORAoO
0
Cornellus1985 Messages postés 22 Date d'inscription dimanche 26 avril 2009 Statut Membre Dernière intervention 7 juillet 2009
30 avril 2009 à 11:34
Merci bien pour ton aide, comme l'application ne marchait pas (il ne faisait que dessiner le frame vide), j'ai entrepris un debug a la robinson en mettant des "sout" un peu partout.
J'ai essaye de remplacer la ligne de code comme tu l'as suggere, mais le resultat reste le meme.
Peut etre pourrais tu m'eclairer, je voudrais juste savoir a quelle occasion le contexte graphique appel la methode update ?
Parce que je me suis rendu compte au final qu'on ne passait jamais dans la methode surchargee update() sauf si j'en fait l'appel explicitement dans mon run(). Je lui passe alors en argument mon attribut "memoryGraphics".

Dans un premier temps, etant donne que le programme n'appelait jamais la methode update et que l'affichage etait nul, c'est-a-dire, pas la moindre image d'affichee, j'ai decide de voir ce qui se passe en redefinissant la mehode paint().

public void run() {

Rectangle edges = new Rectangle(0 + getInsets().left , 0 + getInsets().top ,
getSize().width - ( getInsets().left + getInsets().right ),
getSize().height - ( getInsets().top + getInsets().bottom ));

for (int loopIndex = 0 ; loopIndex < numberFish ; loopIndex++) {

Random x = new Random(System.currentTimeMillis());
int random = generateRandom(x);
fishes.add( new Fish ( fishImages[random] , edges , this ));
try {
Thread.sleep(20);
}
catch (Exception e) {
System.out.println(e.getMessage());
}
}
paintOK = true;
repaint();
}

@Override
public void paint(Graphics g) {
if (paintOK) {
super.paint(g);
g.drawImage(aquariumImage, 0, 0, this);

for ( int loopIndex = 0 ; loopIndex < fishes.size() ; loopIndex++ ) {
fishes.elementAt( loopIndex ).drawFishImage( g );
}
}
}

protected static int generateRandom(Random x) {
int i = Math.abs(x.nextInt(1000));
System.out.println("Math.abs(x.nextInt()) = " + i);
int rand = i % 2;
return rand;
}

J 'obtiens un affichage cette fois-ci, avec l'image de fond de mon panel (aquariumImage), ainsi que 10 poissons positionnes aleatoirement sur mon panel.
Il ne me reste plus qu'a les faire nager et j'aurais besoin d'un petit coup de pouce.
Toute aide sera la bienvenue.
Merci d'avance
A+
0
Twinuts Messages postés 5375 Date d'inscription dimanche 4 mai 2003 Statut Modérateur Dernière intervention 14 juin 2023 111
30 avril 2009 à 21:25
Salut,

là comme ça sans avoir testé le code ni même regardé le code plus en détail je ne vois pas trop ton pb. Cependant pour le type d'application que tu cherches à faire je ne comprend pas vraiment pourquoi tu t'obstines à utiliser le pain natif à java à la place du BufferStrategy + sprites & Co (utilisé pour les jeux en bypassant les paints java et te laissant gérer le tout par toi même - possibilitée d'utiliser le triple buffuring -) ce qui est (à mon sens) le plus adapté à ton cas.

Pour info ICI il y a un exemple concret d'utilisation.

------------------------------------
"On n'est pas au resto : ici on ne fait pas dans les plats tout cuits ..."

OoWORAoO
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Cornellus1985 Messages postés 22 Date d'inscription dimanche 26 avril 2009 Statut Membre Dernière intervention 7 juillet 2009
1 mai 2009 à 11:37
Merci je vais y jeter un coup d'oeil mais avant je finis ce que j'ai commence. C'est presque fini a mon avis. J'ai juste a implementer la partie ou on rafraichie le dessin avec la nouvelle location des poissons en double-buffering a l'aide d'un thread et ensuite on affiche, des que la BufferedImage a ete update.
Voila voila merci pour ton aide.
A+
0
Rejoignez-nous