2011-09-14 2 views
1

Je construis mon premier jeu en Java, à partir de zéro. J'ai décidé que la classe GameWorld, qui centralise les opérations principales du jeu (gestion des entrées, etc.), serait mieux implémentée en tant que singleton (en utilisant une énumération). Le code correspondant à l'énumération est ci-dessous.Java Singleton NullPointerException

public enum GameWorld { 
    INSTANCE; 
    private static InputController input = InputController.getInput(); 
    public EntityPlayer player = new EntityPlayer(10, 10, 5, 5); 

    public static GameWorld getWorld() { 
     return INSTANCE; 
    } 

    public InputController getInputController() { 
     return input; 
    } 
} 

L'exception se produit dans le constructeur de EntityPlayer. Le code et la trace de la pile sont ci-dessous.

public class EntityPlayer implements Entity, InputListener { 
    private int xPos; 
    private int yPos; 
    private int width; 
    private int height; 

    // Velocity of object 
    // Determines where it sets itself on update 
    private int xVel; 
    private int yVel; 
    private GameWorld world; 

    private InputController input; 

    private boolean solid; 

    public EntityPlayer(int x, int y, int width, int height) { 
     xPos = x; 
     yPos = y; 
     this.width = width; 
     this.height = height; 
     solid = true; 
     xVel = 0; 
     yVel = 0; 
     world = getWorld(); 
     input = world.getInputController(); 
     input.registerKeyListener(this); 
    } 

    @Override 
    public Graphics draw(Graphics g) { 
     g.setColor(Color.yellow); 
     g.fillRect(xPos, yPos - height, width, height); 
     return g; 
    } 

    @Override 
    public void update() { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    @Override 
    public int getXPos() { 
     return xPos; 
    } 

    @Override 
    public int getYPos() { 
     return yPos; 
    } 

    @Override 
    public Rectangle getRect() { 
     throw new UnsupportedOperationException("Not supported yet."); 
    } 

    @Override 
    public boolean isSolid() { 
     return solid; 
    } 

    @Override 
    public void kill() { 

    } 

    @Override 
    public GameWorld getWorld() { 
     return GameWorld.getWorld(); 
    } 

    @Override 
    public void sendKeyPress(KeyEvent ke) { 
     System.out.println(ke.getKeyChar()); 
    } 

    @Override 
    public void sendMouseMove(MouseEvent me) { 

    } 

} 

La trace de la pile:

Exception in thread "main" java.lang.ExceptionInInitializerError 
    at com.pvminecraft.gameworld.Main.<clinit>(Main.java:14) 
Caused by: java.lang.NullPointerException 
at com.pvminecraft.gameworld.entities.EntityPlayer.<init>(EntityPlayer.java:45) 
at com.pvminecraft.gameworld.GameWorld.<init>(GameWorld.java:15) 
at com.pvminecraft.gameworld.GameWorld.<clinit>(GameWorld.java:13) 
... 1 more 

Ligne 14 de Main.java me devient une autre instance de GameWorld pour les tests. Je ne sais pas pourquoi cela lance une exception. Si je supprime des références à GameWorld dans EntityPlayer, cela disparaît. Si vous avez besoin du code pour Main.java, dites-moi dans les commentaires et je l'afficherai. Merci!

EDIT: La ligne 45 dans EntityPlayer est "input = world.getInputController();" Je suis assez sûr que le monde est nul, bien que je ne sache pas pourquoi.

+1

Qu'est-ce que la ligne 45? Oh, ça? 'input = world.getInputController();'? –

+2

Ce n'est pas un bon usage d'un 'enum' ... –

+0

J'ai eu l'idée de ceci: http://stackoverflow.com/questions/70689/efficient-way-to-implement-singleton-pattern-in-java Il a été très bien noté, et il a cité un livre dont j'ai entendu parler comme étant bon. J'ai supposé que c'était correct. Ai-je tort? –

Répondre

2

Vous vous transformez en cercles.

Vous souhaitez initialiser la variable GameWorld.INSTANCE. Avant de pouvoir le faire, vous devez initialiser tous les champs de la classe GameWorld. Après avoir initialisé tout le champ, la variable INSTANCE sera affectée. Avant cela, il a toujours la valeur par défaut null.

Lors de l'initialisation, le champ player est initialisé. Et dans cette initialisation, vous avez déjà accès au champ INSTANCE. Donc vous avez une dépendance circulaire.

Vous devez vraiment découpler vos classes, afin qu'elles deviennent plus indépendantes les unes des autres.

+0

Très bien alors.Je vais. Merci. –

+0

+1 Bonne prise. Je venais de comprendre comment 'INSTANCE' était' null' quand vous avez posté ceci. –

+0

Je ne suis pas encore tout à fait clair sur la meilleure façon de le faire. J'ai ajouté une méthode setPlayer qui fonctionne pour le moment. Merci. –

0

Je ne vois aucune garantie que l'expression

InputController.getInput() 

retours non nul. Et puisque votre code est très facile à déboguer (au moins une exception NullPointerException par ligne), il devrait être trivial de voir quelle variable est nulle. Comme je l'ai dit, je suspecte input.

+0

C'est le monde. J'ai déjà fait des copies pour le débogage dans le passé, qui me le disent. –