General Main Loop & GUI Problem

Hi Java Gaming Com,
I am currently trying to make a game in java, but failed already with the basic.
Iam building an RTSG with nearly no animations for the begining and got most of my knowledge from tutorials like the space invader game and killer game programming.
I Thought of Having one Game routine, wich paints, when needed(not jet integrated) an board.
There Boards implement MouseListeners and a paint Method.
On Creation they register themself @the Game as Listener and remove themself when they are not any longer shown.
By now i have 2 different board, the GalaxyView with witch the Game starts and no problem occur, but when i Switch to the System View there are RandomNullpointers all during the paint method.
My Guess is, that the paint method of the SystemView is called even though the Object is not yet fully created Even though i dont really understand how this can happen.
Since stepping through the expressions with the debugger does prevent the bug from happening i guess it has something to do with Threading.

Comments & Hints and Advise are all appreciated and at this point let me apologize for my bad english ^^

I hope the code i post is enough.

public class Game extends Canvas {
    /** The stragey that allows us to use accelerate page flipping */
    private BufferStrategy strategy;
    /** True if the game is currently "running", i.e. the game loop is looping */
    private boolean gameRunning = true;
    /** True if game logic needs to be applied this loop, normally as a result of a game event */
    private boolean logicRequiredThisLoop = false;
    /** The last time at which we recorded the frame rate */
    private long lastFpsTime;
    /** The current number of frames recorded */
    private int fps;
    /** The game window that we'll update with the frame count */
    private JFrame container;

    private Board board;

    public Game() {
        container = new JFrame("Space Exploration");
        board= new GalaxyWrapper(this);
        JPanel panel = (JPanel) container.getContentPane();
        panel.setPreferredSize(new Dimension(GRAPHICALCONSTANTS.width, GRAPHICALCONSTANTS.height));
        panel.setLayout(null);
        setBounds(0, 0, GRAPHICALCONSTANTS.width, GRAPHICALCONSTANTS.height);
        panel.add(this);
        setIgnoreRepaint(true);

        container.pack();
        container.setResizable(false);
        container.setVisible(true);


        requestFocus();

        createBufferStrategy(2);
        strategy = getBufferStrategy();
        container.setDefaultCloseOperation(container.EXIT_ON_CLOSE);

    }

    public void gameLoop() {
        long lastLoopTime = System.nanoTime();
        

        while (gameRunning) {

          long delta = (System.nanoTime()-lastLoopTime);
          lastLoopTime = System.nanoTime();
          
            lastFpsTime += delta;
            fps++;

            if (lastFpsTime >= 1e9) {
                container.setTitle("Space Exploration (FPS: " + fps + ")");
                lastFpsTime = 0;
                fps = 0;
            }

            Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
            board.paint(g, this);
            g.dispose();
            strategy.show();
            redraw=false;
            
            
            try {

                Thread.sleep(Math.max(1,10-(System.nanoTime()-lastLoopTime)/1000000));
            } catch (InterruptedException e) {
            }
        }
    }
   public void setRedraw(Boolean redraw) {
        this.redraw = redraw;
    }

    public Board getBoard() {
        return board;
    }

    public void setBoard(Board board) {
        this.board = board;
    }
}

public interface Drawable {
    public void paint(Graphics2D g,ImageObserver im);
}

public abstract class Board extends MouseAdapter implements Drawable{
    private Game game;
    public Board(Game game){
        this.game=game;

        game.setBoard(this);
        game.addMouseListener(this);
        game.setRedraw(true);
    }

    public void removeMouseListener(){
        game.removeMouseListener(this);
    }
    public Game getGame(){
        return game;
    }
}
public class GalaxyWrapper extends Board {

    private Image background;
    private Quadrant galaxy=new Quadrant();

    public void paint(Graphics2D g, ImageObserver im) {
        int h=background.getHeight(im);
        int w=background.getWidth(im);
        int xAnZahl = (int)GRAPHICALCONSTANTS.height/h+1;
        int yAnZahl = (int)GRAPHICALCONSTANTS.width/w+1;
        for(int i=0;i<yAnZahl;i++){
            for(int ii=0;ii<xAnZahl;ii++){
                g.drawImage(background, 0+ii*h, 0+i*w, im);
            }
        }
        
        g.setColor(Color.DARK_GRAY);
        g.drawLine(290, 0, 290, 580);//425
        g.drawLine(0, 290, 580, 290);
        g.setFont(new Font("Purisa", Font.PLAIN, 13));
        g.setColor(Color.ORANGE);
        g.drawString("GAMMA", 145, 145);
        g.drawString("BETA", 435, 435);
        g.drawString("ALPHA", 145, 435);
        g.drawString("DELTA", 435, 145);
        SolarSystem[][] ss = galaxy.getGalaxy();
        System.out.println("@muh "+ss[0].length+":"+ss.length);
        for (int i = 0; i < CONSTANTS.GALAXYGROESSEX; i++) {
            for (int ii = 0; ii < CONSTANTS.GALAXYGROESSEY; ii++) {
                SolarSystem solsys = ss[i][ii];
                if (solsys != null) {
                    g.drawString(i+""+ii,i*30+10,ii*30+10);
                    g.drawImage(new ImageIcon(Game.class.getResource("../IMAGES/Icons/Uni/sun" + solsys.getSun().getID() + ".png")).getImage(), 10+i * 30, 10+ii * 30, im);
                    
                }
            }
        }
    }
    
    public GalaxyWrapper(Game game) {
        super(game);
        System.out.println(this.getClass().getResource("../IMAGES/Icons/Uni/bg_stars1.gif").getPath());
        background = new ImageIcon(Game.class.getResource("../IMAGES/Icons/Uni/bg_stars1.gif")).getImage();
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        super.mouseClicked(e);
        int xkoord=e.getX();
        int ykoord=e.getY();
        int i=(xkoord-10)/30;
        int ii=(ykoord-10)/30;
        System.out.println(i+":"+ii);
        removeMouseListener();
        new SolarSystemView(getGame(), galaxy.getGalaxy()[i][ii]);
    }
    


}
public class SolarSystemView extends Board implements MouseListener, Runnable {

    Random random = new Random();
    int width = 800, height = 600;
    private SolarSystem system;
    Thread m_orbit = new Thread(this);
    boolean changingPlanets=false;    

    public void run() {
        try {
            while(true){
            
            for (PlanetWrapper planet : solarSystem) {
                planet.rotate(10);
                
            }                        
            Thread.sleep(100);
            }
        } catch (InterruptedException e) {
            m_orbit.interrupt();
        }

    }
    private BufferedImage background;
    private BufferedImage offImage;
    private Graphics dbg;

    public void mouseClicked(MouseEvent e) {
    if(e.getButton()==e.BUTTON3){
        
        
    }
    }

    public void mouseEntered(MouseEvent e) {
        ;
    }

    public void mouseExited(MouseEvent e) {
        ;

    }

    public void mousePressed(MouseEvent e) {
        ;
    }

    public void mouseReleased(MouseEvent e) {
        ;
    }
    private  PlanetWrapper[] solarSystem;
    private BufferedImage sun;

    public void generateSolarSystem() {
        try {
            
            System.out.println(SolarSystemView.class.getResource("../IMAGES/Icons/Planets/RedDwarf.gif").getPath());
            solarSystem = new PlanetWrapper[system.getOrbits().length];
            switch (system.getSun().getID()) {
                case 0:
                    sun = ImageIO.read(SolarSystemView.class.getResource("../IMAGES/Icons/Planets/RedDwarf.gif"));
                    break;
                case 1:
                    sun = ImageIO.read(SolarSystemView.class.getResource("../IMAGES/Icons/Planets/RedGiant.gif"));
                    break;
                case 2:
                    sun = ImageIO.read(SolarSystemView.class.getResource("../IMAGES/Icons/Planets/YellowDwarf.gif"));
                    break;
            }
            int i = 0;
            for (Planet planet : system.getOrbits()) {
                solarSystem[i] = new PlanetWrapper(planet,((height-sun.getHeight())/2/solarSystem.length*i)+sun.getHeight()/2);
                i++;
            }

            System.out.println("0"+sun==null);
            background = ImageIO.read(SolarSystemView.class.getResource("../IMAGES/Icons/Planets/background.gif"));

            GraphicsConfiguration gfxConf = GraphicsEnvironment.getLocalGraphicsEnvironment().
                    getDefaultScreenDevice().getDefaultConfiguration();

            offImage = gfxConf.createCompatibleImage(width, height);
            
        } catch (IOException e) {
            System.err.println("IOException thrown 45");
        }
    }

    public SolarSystemView(Game game,SolarSystem system) {
        super(game);
        this.system = system;        
        generateSolarSystem();
    }

    public void paint(Graphics2D g, ImageObserver im) {
        if (offImage == null) {

            offImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        }
        if(sun!=null){
        dbg = offImage.getGraphics();
        dbg.drawImage(background, 0, 0, im);
        dbg.translate(width/2, height/2);

        dbg.setColor(Color.WHITE);
        
        //dbg.drawImage(this.solarSystem[0], 0, height/2-solarSystem[1].getHeight()/2, this);
        dbg.drawImage(sun, 0-sun.getWidth()/2,0-sun.getHeight()/2, im);
        for (int i = 1; i < solarSystem.length; i++) {
            System.out.println(i+""+solarSystem[i]==null);
            int orbit = (int)(solarSystem[i].getOrbit());//+solarSystem[i].getImage().getWidth()/7);
            dbg.drawOval((0-orbit), (0-orbit),2*orbit,2*orbit);
            dbg.drawImage(solarSystem[i].getImageR(), (int)solarSystem[i].getX()-solarSystem[i].getImageR().getWidth()/2, (int)solarSystem[i].getY()-solarSystem[i].getImageR().getHeight()/2, im);
        }
        dbg.translate(-width/2,-height/2);




        g.drawImage(offImage, 0, 0, im);
    }
    }
}

sry for double posting but there is a cap on posts : /

public class PlanetWrapper {
    private Planet planet;
    private BufferedImage image;
    private double degreesRotation;
    private double degreesTraRot;
    private double degreesTraRotSpeed=Rand.getNextFloat()/4+0.1;
    private double x,y=0;
    private double orbit=0;



    public BufferedImage getImage() {
        return image;
    }

    public Planet getPlanet() {
        return planet;
    }

    public double getX() {
        return x;
    }

    public double getY() {
        return y;
    }
    public PlanetWrapper(Planet planet,int radius){
        this.planet=planet;
        this.orbit=radius;
        degreesTraRot=Rand.getNextInt(360);
        move();
        try{
        image=ImageIO.read(PlanetWrapper.class.getResource("../IMAGES/Icons/Planets/"+planet.getPlanetClass().getTypeName()+".gif"));
        }catch(IOException e){
            System.err.println("Failed to load planet gif in PlanetWrapper");
        }
    }

    public PlanetWrapper(Planet planet, int degrees, int x,int y) {
        this.planet = planet;
        this.degreesRotation = degrees;
        this.x = x;
        this.y=y;
    }
    
    public PlanetWrapper(Planet planet,BufferedImage image){
        this.planet=planet;
        this.image=image;
    }
    public void rotate(double degrees){
        this.degreesRotation+=degrees;
        this.degreesRotation%=360;
        move();
    }

    public double getOrbit() {
        return orbit;
    }
  
    public void move(){
     degreesTraRot+=degreesTraRotSpeed;
     degreesTraRot%=360;
    x= orbit*Math.cos(degreesTraRot*Math.PI/180);
    y= Math.sin(degreesTraRot*Math.PI/180)*orbit; 


    }
    public BufferedImage getImageR(){
        return rotateImage(image,this.degreesRotation);
    }
    private static BufferedImage rotateImage(BufferedImage src, double degrees) {
        AffineTransform affineTransform = AffineTransform.getRotateInstance(
                Math.toRadians(degrees),
                src.getWidth() / 2,
                src.getHeight() / 2);
        BufferedImage rotatedImage = new BufferedImage(src.getWidth(), src
                .getHeight(), src.getType());
        Graphics2D g = (Graphics2D) rotatedImage.getGraphics();
        g.setTransform(affineTransform);
        g.drawImage(src, 0, 0, null);
        return rotatedImage;
    }       
}

no tips or hints?
Iam really stuck here couse i cant find another approach : /

Can you replicate your problem using a simpler example of your problem? You are potentially putting people “off” by so much code.

My suggestion is to reduce the problem to its smallest possible code size. You may even find your problem in the process!

thx ill try

thank you for all that code samples !
I think you’re on the right way with such a pattern. However there are some mistakes with your transforms :


 dbg.translate(width/2, height/2);

        dbg.setColor(Color.WHITE);
        
        //dbg.drawImage(this.solarSystem[0], 0, height/2-solarSystem[1].getHeight()/2, this);
        dbg.drawImage(sun, 0-sun.getWidth()/2,0-sun.getHeight()/2, im);
        for (int i = 1; i < solarSystem.length; i++) {
            System.out.println(i+""+solarSystem[i]==null);
            int orbit = (int)(solarSystem[i].getOrbit());//+solarSystem[i].getImage().getWidth()/7);
            dbg.drawOval((0-orbit), (0-orbit),2*orbit,2*orbit);
            dbg.drawImage(solarSystem[i].getImageR(), (int)solarSystem[i].getX()-solarSystem[i].getImageR().getWidth()/2, (int)solarSystem[i].getY()-solarSystem[i].getImageR().getHeight()/2, im);
        }
        dbg.translate(-width/2,-height/2);

  1. java numbers are quite flexible, double can be long and float can be int, without explicit casting. But as of the translate() operation, there are two similar definitions of the function, one using double and the other using int. the first does a translation, while the latter does origin translation which is not the same in terms of matrix product. then the issue with using “implicit” casting e.g. translate(width/2, height/2) may return a wrong type, in such case an “explicit” casting is necessary :
dbg.translate((double)width/2.0, (double)height/2.0) will do matrix translation
or
 dbg.translate((int)Math.round(width/2.0), (int)Math.round(height/2.0)) will make an x,y origin translation
  1. Also, it is important to minimize disk access, whereas the ImageIO.read(ResourceURL) does make a lot of disk usage if repeated.