我在制作基于文本的游戏时遇到问题。我对Java和在Java中绘制GUI相当陌生,因此我怀疑我的整体结构可能是问题的根源。所以忍受我吧
我的主类,实例化一个新的Gamelobby()。
class untitledRPG {
public static void main(String[] args) { new GameLobby(); }
}
GameLobby实例化MainMenu()。
class GameLobby {
{
mainMenu = new MainMenu();
}
}
MainMenu()如下所示,如果玩家选择“ New Game”(新游戏)按钮以及Intro()(该游戏文字将来自此),则将GameWindow()设置为空。
public class MainMenu {
private String newGame;
private String loadGame;
private String settings;
private JFrame frame = new JFrame("UntitledRPG™ Main Menu");
public MainMenu() {
newGame = "New Game";
loadGame = "Load Game";
settings = "Settings";
buildWindow(frame);
}
private void buildWindow(JFrame frame)
{
// Main build
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(400, 220);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
// Draw layout with grid
// Look into GridBagLayout if this proves insufficient
frame.setLayout(new GridLayout(3,1));
JPanel field1 = new JPanel();
JPanel field2 = new JPanel(new GridLayout(1, 3));
JPanel field21 = new JPanel();
JPanel field22 = new JPanel();
JPanel field23 = new JPanel();
field2.add(field21);
field2.add(field22);
field2.add(field23);
JPanel field3 = new JPanel();
// Instantiate objects
JLabel welcomeTextLabel = new JLabel();
JLabel gameDescLabel = new JLabel();
JButton newGameBtn = selectGameTypeBtn(newGame);
JButton loadGameBtn = selectGameTypeBtn(loadGame);
JButton settingsBtn = selectGameTypeBtn(settings);
// Set values. Can be integrated to the instantiation
String welcomeText = "Welcome to the Untitled RPG!";
String gameDesc = "<html>Press 'New Game' to start your adventure,<br /> or 'Load Game' to continue an existing one!</html> ";
settingsBtn.setText("Settings");
welcomeTextLabel.setText(welcomeText);
gameDescLabel.setText(gameDesc);
//Add objects to panels
field1.add(welcomeTextLabel);
field21.add(newGameBtn);
field22.add(loadGameBtn);
field23.add(settingsBtn);
field3.add(gameDescLabel);
// Add panels to grid
frame.add(field1);
frame.add(field2);
frame.add(field3);
frame.setVisible(true);
}
private JButton selectGameTypeBtn(String btnName) {
JButton returned = new JButton(btnName);
returned.addActionListener(e -> {
JButton source = (JButton)e.getSource();
if (source.getText().equalsIgnoreCase(newGame)) {
new GameWindow().openGameWindow();
new Intro();
frame.dispose();
}
if (source.getText().equalsIgnoreCase(loadGame)) {
popUp popUp = new popUp();
popUp.popUpWindow("You have no saves to load!", "Error!");
}
if (source.getText().equalsIgnoreCase(settings)) {
popUp popUp = new popUp();
popUp.popUpWindow("We haven'made any settings yet!", "Error!");
}
});
return returned;
}
}
GameWindow()看起来像这样:
public class GameWindow {
private JTextArea sideBarArea;
private JTextArea gameArea;
private JTextArea inputAreaTextArea;
private JTextField inputAreaTextField;
private GridBagConstraints c;
public GameWindow() {
c = new GridBagConstraints();
c.anchor = GridBagConstraints.FIRST_LINE_START;
int hGap = 5;
int vGap = 5;
c.insets = new Insets(hGap, vGap, hGap, vGap);
}
public void openGameWindow() {
JFrame frame = new JFrame("UntitledRPG™");
buildGameWindow(frame);
}
private void buildGameWindow(JFrame frame) {
/* GameWindow build info
GameWindow consists of:
- gameArea, a JTextField where the output from the game will be printed.
- sideBarArea, TODO
- inputArea, a JPanel where the player enters commands and views them in a log
*/
// Main build
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(700, 600);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
// Set areas
gameArea = new JTextArea(5, 10);
sideBarArea = new JTextArea(5, 10);
JPanel inputArea = new JPanel(new GridBagLayout());
// GAME AREA
gameArea.setEditable(false);
gameArea.setCaretPosition(gameArea.getDocument().getLength());
JScrollPane gameAreaScrollPane = new JScrollPane(gameArea);
//SIDEBAR AREA
sideBarArea.setEditable(false);
// INPUT AREA.
// Set textArea and add it to scrollpane, which is then added to the layout
inputAreaTextArea = new JTextArea(10,20);
inputAreaTextArea.setEditable(false);
inputAreaTextArea.setCaretPosition(inputAreaTextArea.getDocument().getLength());
// Message in the inputAreaTextArea to user.
String welcomeMsg= "This is your command log. Your commands will be printed here.";
printToLog(welcomeMsg);
JScrollPane textAreaScrollPane = new JScrollPane(inputAreaTextArea);
// (addComp) method for placing elements in gridBagLayout.
addComp(inputArea, textAreaScrollPane, 0, 1, 1, 1, GridBagConstraints.BOTH, 2, 2);
// Label with user instruction on using the inputAreaTextField
JLabel inputAreaLabel = new JLabel("Enter commands below.");
addComp(inputArea, inputAreaLabel, 0,2, 1, 1, GridBagConstraints.BOTH, 0.2,0.2);
// Set jTextfield and add it to layout
inputAreaTextField = new JTextField();
inputAreaTextField.setText("Start your adventure!"); // Placeholder, see method below
addComp(inputArea, inputAreaTextField, 0, 3, 2, 2, GridBagConstraints.BOTH, 0.2, 0.2);
// Listener for enter-click
inputAreaTextField.addActionListener((e -> {
if(inputAreaTextField.getText().length() > 0) {
printToLog(inputAreaTextField.getText());
inputAreaTextField.setText("");
}
}));
// Method for the placeholder text. Show up one time before textField is in focus
inputAreaTextField.addFocusListener(new FocusAdapter() {
public void focusGained(FocusEvent e) {
JTextField source = (JTextField)e.getComponent();
source.setText("");
source.removeFocusListener(this);
}
});
// ASSEMBLY
// Set vertical splitpane. Second layer
JSplitPane vertSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, gameArea, sideBarArea);
vertSplitPane.setDividerLocation(500);
vertSplitPane.setDividerSize(10);
vertSplitPane.setEnabled(false);
// Set horizontal split. Top layer
JSplitPane horiSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, vertSplitPane, inputArea);
vertSplitPane.setOneTouchExpandable(false);
horiSplitPane.setDividerLocation(400);
horiSplitPane.setDividerSize(5);
horiSplitPane.setEnabled(false);
frame.add(horiSplitPane);
}
// Easier implementation of constraints for gridBagLayout
private void addComp(JPanel panel, JComponent comp
, int x, int y, int gWidth
, int gHeight, int fill
, double weightx, double weighty) {
c.gridx = x;
c.gridy = y;
c.gridwidth = gWidth;
c.gridheight = gHeight;
c.fill = fill;
c.weightx = weightx;
c.weighty = weighty;
panel.add(comp, c);
}
// Prints player command to inputAreaTextField (log)
public void printToLog(String text) {
inputAreaTextArea.append(">" + text + "\n");
inputAreaTextArea.setCaretPosition(inputAreaTextArea.getDocument().getLength());
}
public void printToGameArea(String text) {
gameArea.append(">" + text + "\n");
gameArea.setCaretPosition(gameArea.getDocument().getLength());
}
}
Intro()看起来像这样:
public class Intro {
Print print;
Player player;
public Intro()
{
player = new Player();
print = new Print();
player = charCreation();
}
private Player charCreation() {
GameWindow gameWindow = new GameWindow();
gameWindow.printToGameArea("Wake up");
player.setAge(21);
player.setName("Kris");
player.setGender("m");
return player;
}
}
但是当我运行它时,我得到这个nullPointerException:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at GUI.GameWindow.printToGameArea(GameWindow.java:138)
at Gameplay.Intro.charCreation(Intro.java:21)
at Gameplay.Intro.<init>(Intro.java:16)
at GUI.MainMenu.lambda$selectGameTypeBtn$0(MainMenu.java:78)
我无法解决造成这种情况的原因,以及如何改善整体结构。
提前感谢您的帮助,如果我的问题不符合SO标准,请告诉我。我也是这个新手。
答案 0 :(得分:0)
在调用printToGameArea初始化组件之前,您需要调用openGameWindow并最终调用buildGameWindow。
private Player charCreation() {
GameWindow gameWindow = new GameWindow();
gameWindow.openGameWindow();
gameWindow.printToGameArea("Wake up");
player.setAge(21);
player.setName("Kris");
player.setGender("m");
return player;
}