Hello everyone !
I’m currently making a 2D RPG in the final fantasy/breath of fire style. It is turn-based during battles only, and the battle screen and the world map/village maps are different screens. I’m writing it using the swing and java2D APIs, and am having 2 problems, both related to passive rendering.
I’ve implemented it so that the player can walk around the world until a random encounter occurs. Then, the world map (represented in the code at the end of the post as gamePanel) is essentially put on “hold” and the battle screen (represent in the code at the end of the post as battPanel) is displayed. Once the battle is over, the battle screen is removed from the frame, and the world map is “unpaused.”
The first problem is that the game sometimes freezes while the user is walking aroudn the world map, and sometimes doesn’t know that it is time for a battle. I think that this problem is related to threading. See the code below.
The second problem is that the battle panel does not always render. I have a feeling that this is not an image-loading time related problem because i just ran the program with the following paintComponent method and it still did not work every time:
public void paintComponent(Graphics g) {
super.paintComponent(g);
//I’ve done the following two lines with an explicitly casted graphics2D object and with the standard Graphics object that is passed in
g.setFont(font); //font was previously initialized like this: private Font font = new Font(“SansSerif”, Font.PLAIN, 15);
g.drawString(“Hello!”, 20, 20);
}
I’m much more concerned with the second problem than the first, because if I have a game that only displays battles whenever it wants to… well… that’s hardly a game at all. Here is the code for my main game loop. There are three different versions. One is the original version, the next was updated to follow a friend’s advice (and it works quite well, actually), and the same for the third version. The second and third versions use threading, which I am a total stranger to.
Just so you know, i can get the world map displaying perfectly… just not the battle screen. Does that mean that the error is in the battlepanel class? Normally I would say yes, except for the paintComponent() test run that I did (see above). I also ran one with an almost empty constructor, and it still only rendered sometimes.
P.S. In battlepanel i hooked keyboard input into a repaint method, so if the user presses enter, a repaint method is dispatched. I only did this for debugging, and it doesn’t work. I tried it with invalidate(), still didn’t work.
Version 1:
public class CGame {
public static void main(String[] args) {
boolean battleRunning = false;
ImageFrame frame = new ImageFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.requestFocusOnSplashPanel(); //There is a splash panel that is initialized and displayed in the frame’s constructor
while(frame.timeToStartGameYet() == false) { //I.E. hasn’t started yet, changed to true by pressing enter
//do nothing
}
//When it is time to start the game, start it.
frame.hideSplashPanel();
frame.removeSplashPanel();
//Put the game panel on the frame while there is no battle
ImagePanel gamePanel = new ImagePanel();
frame.add(gamePanel);
frame.requestFocusOnPanel(gamePanel);
frame.show();
BattlePanel battPanel = null;
while(battleRunning == false) { //I think that the program is choking up because the while loop is too tight
if(gamePanel.getBattleMode() == true) {
System.out.println("battle mode == true");
frame.hidePanel(gamePanel);
battPanel = new BattlePanel(gamePanel.getPlayer());
frame.add(battPanel);
frame.showPanel(battPanel);
frame.requestFocusOnPanel(battPanel);
}
while(gamePanel.getBattleMode() == true) {
//do Nothing
}
//then, when it is over,
battleRunning = false; //Should be false anyway, but just in case :)
if(battPanel != null) {
frame.hidePanel(battPanel);
frame.removePanel(battPanel);
frame.showPanel(gamePanel);
frame.requestFocusOnPanel(gamePanel);
}
}
}
}
Version 2:
public class CGame {
public static void main(String[] args) {
boolean battleRunning = false;
ImageFrame frame = new ImageFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.requestFocusOnSplashPanel(); //There is a splash panel that is initialized and displayed in the frame
while(frame.timeToStartGameYet() == false) { //I.E. hasn’t started yet, changed to true by pressing enter
//do nothing
}
//When it is time to start the game, start it.
frame.hideSplashPanel();
frame.removeSplashPanel();
ImagePanel gamePanel = new ImagePanel();
frame.add(gamePanel);
frame.requestFocusOnPanel(gamePanel);
frame.show();
BattlePanel battPanel = null;
while(battleRunning == false) {
if(gamePanel.getBattleMode() == true) {
System.out.println("battle mode == true");
frame.hidePanel(gamePanel);
battPanel = new BattlePanel(gamePanel.getPlayer());
frame.add(battPanel);
frame.showPanel(battPanel);
frame.requestFocusOnPanel(battPanel);
}
while(gamePanel.getBattleMode() == true) {
//do Nothing
Thread.yield();
}
//then, when it is over,
battleRunning = false;
if(battPanel != null) {
frame.hidePanel(battPanel);
frame.removePanel(battPanel);
frame.showPanel(gamePanel);
frame.requestFocusOnPanel(gamePanel);
}
try {
Thread.sleep(10);
}
catch (InterruptedException e) {
System.out.println("E messed up in main!");
}
}
}
Version 3:
public class CGame {
public static void main(String[] args) {
boolean battleRunning = false;
ImageFrame frame = new ImageFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.requestFocusOnSplashPanel();
while(frame.timeToStartGameYet() == false) { //I.E. hasn’t started yet
//do nothing
}
//When it is time to start the game, start it.
frame.hideSplashPanel();
frame.removeSplashPanel();
//Put the game panel on the frame while there is no battle
ImagePanel gamePanel = new ImagePanel();
frame.add(gamePanel);
frame.requestFocusOnPanel(gamePanel);
frame.show();
BattlePanel battPanel = null;
synchronized(gamePanel) {
while(gamePanel.getBattleMode() != true) {
try {
System.out.println("in while gamepanel's battleMode == false, current battle mode is: " + gamePanel.getBattleMode());
if(gamePanel.getBattleMode()) {
System.out.println("About to wait all threads!");
System.out.println("battle mode == true");
frame.hidePanel(gamePanel);
battPanel = new BattlePanel(gamePanel.getPlayer());
frame.add(battPanel);
frame.showPanel(battPanel);
frame.requestFocusOnPanel(battPanel);
gamePanel.wait();
}
}
catch (InterruptedException e) {
System.out.println("Error in waiting frame thread.");
}
//do Nothing
}
}
//then, when it is over,
synchronized(gamePanel) {
gamePanel.notifyAll();
gamePanel.setBattleMode(false);
}
//battleRunning = false;
if(battPanel != null) {
frame.hidePanel(battPanel);
frame.removePanel(battPanel);
frame.showPanel(gamePanel);
frame.requestFocusOnPanel(gamePanel);
battPanel = null;
}
}
}
}
