Hi I'm building a game which includes 3 JPanels on a JFrame, a Startscreen, a DrawingPanel and a GameOver screen. If I just create the DrawingPanel and tell the GameController class to begin updating it works fine, but if I create a StartScreen with a button to start the game, then when I press the start game button the game window does not display, although the game code runs.
EDIT:
I have created a new program which mimics the creation of the JPanels, but excludes all of the game code to make it a bit simpler to follow. Below I have included all the relevant classes:
This class creates a JFrame and two JPanels. It also runs the code that updates the game state and tells the DrawingPanel to repaint.
public class TestController{
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
private final int FRAME_WIDTH = (int)screenSize.getWidth();
private final int FRAME_HEIGHT = (int)screenSize.getHeight();
public boolean gameStarted = false;
private JFrame gameWindow;
private TestDrawingPanel myDrawingPanel;
private TestStartGame startGame;
int counter;
Set<Rectangle> rects;
//creates a JFrame and all the JPanels
public TestController(String title)
{
gameWindow = new JFrame(title);
gameWindow.setSize(FRAME_WIDTH, FRAME_HEIGHT);
gameWindow.setVisible(true);
gameWindow.setResizable(false);
gameWindow.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
startGame = new TestStartGame(getAvailableWidth(), getAvailableHeight());
startGame.addAL(new StartButton());
myDrawingPanel = new TestDrawingPanel(getAvailableWidth(), getAvailableHeight());
gameWindow.add(startGame);
gameWindow.add(myDrawingPanel);
myDrawingPanel.setVisible(false);
myDrawingPanel.setEnabled(false);
rects = new HashSet();
}
private int getAvailableWidth()
{
return gameWindow.getWidth() - gameWindow.getInsets().left - gameWindow.getInsets().right;
}
private int getAvailableHeight()
{
return gameWindow.getHeight() - gameWindow.getInsets().top - gameWindow.getInsets().bottom;
}
//starts the game running
public void startTheGame()
{
myDrawingPanel.setEnabled(true);
startGame.setVisible(false);
startGame.setEnabled(false);
myDrawingPanel.setVisible(true);
gameStarted = true;
update();
}
public boolean getGameStarted()
{
return gameStarted;
}
//loop that runs the game code
public void update()
{
counter = 0;
while(gameStarted)
{
updatePictureState();
myDrawingPanel.draw(rects);
myDrawingPanel.repaint();
}
}
//updates the game state
public void updatePictureState()
{
rects.clear();
for (int i = counter + 10; i < counter + 100; i = i + 10)
{
rects.add(new Rectangle(i,i,10,10));
}
}
//an action listener to be added to the start screen
private class StartButton implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
Object buttonPressed = e.getSource();
if(buttonPressed.equals(TestStartGame.start))
{
startTheGame();
}
}
}
}
This class is an extended JPanel with a single button to start the game:
public class TestStartGame extends JPanel{
private final JPanel buttons;
public static JButton start;
//creates a JPanel with a single button to start the game
public TestStartGame(int width, int height)
{
setSize(width, height);
setLayout(new GridLayout(2,1));
setBackground(Color.GREEN);
buttons = new JPanel();
buttons.setSize(width, height / 2);
buttons.setBackground(Color.red);
start = new JButton("Start");
buttons.add(start);
add(buttons, BorderLayout.SOUTH);
}
//adds an action listener to the button
public void addAL(ActionListener al)
{
start.addActionListener(al);
}
}
This class is an extended JPanel and acts as the main screen for the game, being updated to with each cycle of the game to display it's current state:
public class TestDrawingPanel extends JPanel{
Set<Rectangle> drawSet;
//creates the drawing panel and sets the size and background
public TestDrawingPanel(int width, int height)
{
setSize(width, height);
this.setBackground(Color.CYAN);
drawSet = new HashSet();
}
public void draw(Set<Rectangle> platforms)
{
drawSet.clear();
drawSet = platforms;
}
//draws the game window
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
System.out.println("works here");
g.setColor(Color.red);
for (Rectangle r : drawSet)
{
g.fillRect((int)r.getX(), (int)r.getY(), (int)r.getWidth(), (int)r.getHeight());
}
}
}
If I just add the TestDrawingPanel, it displays fine, but if I start with a TestStartScreen then when I click the start game button the TestStartScreen does not disappear and the TestDrawingPanel never displays. Interestingly, if I have both screens but do not call the update method is TestController then the start game button works correctly and the TestDrawingPanel displays, although obviously nothing happens as the update method is where the game state is changed.
I have discovered the problem is that if the TestDrawingPanel is not the only JPanel created then the call to repaint it fails.