1

I'm building my first game in Java, from scratch. I've decided that the GameWorld class, that centralizes the main operations of the game (handling input, etc), would be best implemented as a singleton (using an enum). The relevant code for the enum is below.

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;
    }
}

The exception occurs in the constructor of EntityPlayer. The code and stack trace are below.

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) {

    }

}

The stack trace:

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

Line 14 of Main.java is me getting another instance of GameWorld for testing. I'm not sure why this is throwing an Exception. If I remove references to GameWorld in EntityPlayer, it goes away. If you need the code for Main.java, tell me in the comments and I will post it. Thanks!

EDIT: Line 45 in EntityPlayer is "input = world.getInputController();" I'm pretty sure that world is null, though I have no idea why.

8
  • 1
    What's line 45? Oh, this? input = world.getInputController();? Commented Sep 14, 2011 at 23:32
  • 2
    This is not a good use of an enum... Commented Sep 14, 2011 at 23:36
  • I got the idea from this: stackoverflow.com/questions/70689/… It was highly rated, and he cited a book that I have heard of as being good. I assumed it was correct. Am I wrong? Commented Sep 14, 2011 at 23:38
  • 2
    @Oli Using an enum as a singleton is arguably the best Java singleton pattern for Java 1.5+. Commented Sep 14, 2011 at 23:39
  • 2
    Hmm, you have a player in the enum, and the player refers to the enum--seems like that could be a potential problem. Commented Sep 15, 2011 at 0:00

2 Answers 2

2

You are turning yourself in circles.

You want to initialize the GameWorld.INSTANCE variable. Before you can do that, you have to initialize all the fields of the GameWorld class. After initializing all the field, the variable INSTANCE will be assigned. Before that happens, it still has the default value of null.

During the initialization, the field player is initialized. And in that initialization, you already access the INSTANCE field. So you have a circular dependency.

You really must decouple your classes, so that they become more independent of each other.

Sign up to request clarification or add additional context in comments.

2 Comments

+1 Good catch. I had just figured out how INSTANCE was null when you posted this.
I'm still not entirely clear on the best way to do that. I've added a setPlayer method which works for now though. Thanks.
0

I didn't see any guarantee that the expression

InputController.getInput()

returns non-null. And since your code is very debugging-friendly (at least one NullPointerException per line) it should be trivial to see which variable is null.

As I said, I suspect input.

1 Comment

It is world. I've had printlns there for debugging in the past, which tell me such.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.