Search code examples
javaslick2d

Java - Slick 2D - Placing text (or any graphics) on a rectangle (or any Shape)


I am making an RTS game using Slick 2D. I have a building class and it contains an int called resources. I want the resources variable to become a string and be rendered onto the center of my building (which is just supposed to be a rectangle).

Here's my building class:

package test;

import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.geom.Rectangle;

public class BaseBuilding extends Rectangle{

    private int resources;
    private Graphics g;

    public BaseBuilding(float x, float y, float width, float height) {
        super(x, y, width, height);
        resources = 0;
        g = new Graphics();
    } // end constructor

    public void render(){
        g.drawString("bro wat", resources, resources);
        g.setColor(Color.gray);
        g.fill(this);
        g.drawString(Integer.toString(resources), this.width/2, this.height/2);
    } // end update

    public int getResources(){
        return resources;
    } // end getResources

    public void addResources(int mulla){
        resources += mulla;
        if (resources < 0) 
            resources = 0;
    } // end addResources

    public void createBasicUnit(){
        // create a BasicUnit object in a randomly, valid position close to this object
        // TODO
    } // end createBasicUnit

} // end class def

So far all my states are working and i got the rectangle to appear appropriately. My g.drawString(str, float, float) code with correct parameters will work on my GameState class(not shown) in its render function, but it gives me this error in my BaseBuilding class:

java.lang.NullPointerException
at org.newdawn.slick.Graphics.drawString(Graphics.java:1366)
at test.BaseBuilding.render(BaseBuilding.java:19)
at test.GameState.render(GameState.java:34)
at org.newdawn.slick.state.StateBasedGame.render(StateBasedGame.java:199)
at org.newdawn.slick.GameContainer.updateAndRender(GameContainer.java:688)
at org.newdawn.slick.AppGameContainer.gameLoop(AppGameContainer.java:411)
at org.newdawn.slick.AppGameContainer.start(AppGameContainer.java:321)
at test.StateBaseGame.main(StateBaseGame.java:22)
Sat Apr 18 03:18:55 EDT 2015 ERROR:Game.render() failure - check the game code.
org.newdawn.slick.SlickException: Game.render() failure - check the game code.
at org.newdawn.slick.GameContainer.updateAndRender(GameContainer.java:691)
at org.newdawn.slick.AppGameContainer.gameLoop(AppGameContainer.java:411)
at org.newdawn.slick.AppGameContainer.start(AppGameContainer.java:321)
at test.StateBaseGame.main(StateBaseGame.java:22)

So i dug around and found out it's this line that's causing me problems:

g.drawString(Integer.toString(resources), this.width/2, this.height/2);

Couldn't find it on the internet; help if you can please thanks.


Solution

  • After taking a look at the Slick source code, your problem comes from the font variable inside the Graphics class which is null.

    You are instantiating Graphics with the default constructor which does not provide a default value for the font variable. And the other one, as the doc says, only the container should be instantiate Graphics.

    So, you should never instantiate Graphics, instead just retrieve it from the GameContainer (getGraphics) which is everywhere, or you can also get g from the render method of your game class (Game, BasicGame, BasicGameState, StateBasedGame, depending on what you use...).

    To keep it simple, just pass your Graphics object through your render method:

    public void render(Graphics g){
        g.drawString("bro wat", resources, resources);
        g.setColor(Color.gray);
        g.fill(this);
        g.drawString(Integer.toString(resources), this.width/2, this.height/2);
    } // end update
    

    And inside your Game:

    render(GameContainer container, Graphics g) {
        myBaseBuilding.render(g);
    }