我可能做错了。有没有更好的办法?

时间:2014-05-03 15:03:05

标签: java swing oop

所以通常当我制作模拟程序(比如这个)时,我会寻找可以改善的情况,以防情况再次发生。

今天我以为我会用基本的OOP(我理解OOP的概念,只是避开了它并且想要清新我的记忆)。所以我决定做一个只在10x10平面和1个玩家(你)上创造3个怪物的小游戏,你可以在任何x / y方向移动你的玩家。我的计划有效,但我无法帮助,但觉得我做错了。

所以我的程序的基本布局是有5个类。一个GUI类,显示游戏并为您提供移动控制的方向按钮,创建怪物的类,创建玩家的类,创建10x10板并跟踪怪物/玩家位置的类,当然还有主类创建所有对象并具有主游戏循环和诸如此类的东西。

我在与主类和GUI类交互时遇到了一些困难。我最后做的是在我的主类中做一个while循环并等待玩家按下开始按钮,一旦玩家按下它(通过动作监听器),GUI类将公共变量(运行)从false设置为true,一旦变量发生变化,我就可以采取相应的行动。

这里我觉得我做错了什么:首先我的while循环不会终止,除非我打印到控制台。我用谷歌搜索了这个问题,显然人们已经说过线程或“活跃的民意调查”这个问题,我不明白。我去了我的程序并在我的while循环中添加了一个小的10ms线程睡眠,一切都开始工作了。

我向你们提问的是,什么是积极的民意调查?为什么不好?在我的程序中如何/为什么/这是怎么回事?最后,如果有更好的方式与GUI类和主类进行交互。对不起文字的巨大墙壁,但我想在解释情况时要彻底!

TL; DR:我是否正确地与GUI类和主类进行交互?如果不是这样做的正确方法是什么?

我的主要课程:

public class MainGame {

public static void main(String[] args) throws InterruptedException{
    ShowGUI gui = new ShowGUI();

    while(!gui.running){
        Thread.sleep(10);
    }

    Board gameBoard = new Board();
    gui.setLabelText(gameBoard.getBoard());

    //Add Player
    Player playerOne = new Player(1000, "Player 1");

    //Add monsters
    Monster monstMatt = new Monster(1000, "Matt");
    Monster monstJon = new Monster(1000, "Jon");
    Monster monstAbaad = new Monster(1000, "Abaad");

    while(gui.running){
        Thread.sleep(10);

        int x, y;
        x = playerOne.getX();
        y = playerOne.getY();

        if(gui.buttonPress != -1){
            if(gui.buttonPress == 1){
                playerOne.move(x, --y);
            }else if(gui.buttonPress == 2){
                playerOne.move(x, ++y);
            }else if(gui.buttonPress == 3){
                playerOne.move(--x, y);
            }else if(gui.buttonPress == 4){
                playerOne.move(++x, y);
            }
            gui.buttonPress = -1;
            gui.setLabelText(gameBoard.getBoard());
        }
    }


}

}

我的GUI类:

public class ShowGUI{

private JTextArea board;
private JButton moveUp;
private JButton moveDown;
private JButton moveLeft;
private JButton moveRight;

public boolean running = false;
public int buttonPress = -1;

public ShowGUI(){
    System.out.println("GUI Successfully Loaded");
    createAndShow();
}

private void createAndShow(){
    JFrame mainFrame = new JFrame("Bad Game");

    addComponents(mainFrame.getContentPane());

    mainFrame.setSize(500, 400);
    mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    mainFrame.setLocationRelativeTo(null);
    mainFrame.setResizable(false);
    mainFrame.setVisible(true);
}

private void addComponents(Container pane){
    pane.setLayout(null);

    board = new JTextArea(1, JLabel.CENTER);
    moveUp = new JButton("Up");
    moveDown = new JButton("Down");
    moveLeft = new JButton("Left");
    moveRight = new JButton("Right");

    moveUp.setBounds(185, 225, 130, 35);
    moveLeft.setBounds(115, 280, 130, 35);
    moveRight.setBounds(255, 280, 130, 35);
    moveDown.setBounds(185, 335, 130, 35);

    board.setEditable(false);
    board.setBounds(115, 30, 270, 145);
    board.setFont(new Font("Consolas", Font.BOLD, 12));

    addActionListeners();

    pane.add(board);
    pane.add(moveUp);
    pane.add(moveRight);
    pane.add(moveLeft);
    pane.add(moveDown);
}

private void addActionListeners(){
    moveUp.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            running = true;
            buttonPress = 1;
        }
    });
    moveDown.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            buttonPress = 2;
        }
    });
    moveLeft.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            buttonPress = 3;
        }
    });
    moveRight.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            buttonPress = 4;
        }
    });

}

public void setLabelText(char[][] boardToShow){
    board.setText(" ");
    for(int i = 0; i < boardToShow.length; i++){
        for(int j = 0; j < boardToShow[i].length; j++){
            board.append(boardToShow[i][j] + "   ");
        }
        board.append("\n ");
    }
}

}

如果您需要我的Board / Monster / Player课程,我可以发布,但我不认为这些课程存在问题。

1 个答案:

答案 0 :(得分:0)

主动民意调查(又名busy waiting)是指一个程序反复检查某些条件是否属实,而且由于我们正在谈论计算机,这通常会很多一秒钟。这很糟糕,因为这意味着进程不断耗尽CPU来检查这种情况,更糟糕的是,因为它占用了大量的CPU,它可以防止条件成为真正的第一名(这就是你的情况)。

我试着用一个比喻解释一下,你的Main类(特别是你的while(gui.running)循环)是老板,GUI类是员工。想象一下,老板每秒都会来找他的员工并问&#34;你做过我要求你做的事吗?&#34; 。通过这样做每一秒,不仅老板浪费他的时间,而且实际上是在阻止他的员工做他被要求做的事情。

这正是您的Main类和GUI类之间发生的事情。当buttonPress循环继续运行时while的值不能改变,这就是为什么要睡觉(以及打印到控制台,因为这需要一个IO操作,这也会阻塞线程一段时间) )使它工作,因为while循环停止执行很短的时间,让你的程序有机会改变buttonPress的值。


解决方案

为了解决这个问题,让我们回到老板/员工的比喻中。老板应该说,而不是每秒检查,&#34;当你完成这件事时,来告诉我&#34; 。这样他就不需要继续检查员工,员工有时间完成任务。同样,当actionListeners被触发时,您的GUI类应该调用Main类中的方法。最终,正如其他人所指出的那样,你的结构需要相当多的工作和清理,我建议你考虑使用Model-View-Controller模式。

但是,我会提出一个适用于您目前设置的解决方案。您的主要课程应该类似于:

public class Main {

     private Player playerOne;
     private Monster monstMatt;
     private Monster monstJon;
     private Monster monstAbaad;
     private ShowGUI gui;
     private Board gameBoard;

     public Main() {

         //Add Player
         playerOne = new Player(1000, "Player 1");

         //Add monsters
         monstMatt = new Monster(1000, "Matt");
         monstJon = new Monster(1000, "Jon");
         monstAbaad = new Monster(1000, "Abaad");        

         gui = new ShowGUI(this);

         gameBoard = new Board();
         gui.setLabelText(gameBoard.getBoard());

     }

     public movePlayerUp() {
         movePlayer(0, -1);
     }

     public movePlayerDown() {
         movePlayer(0, 1);
     }

     public movePlayerLeft() {
         movePlayer(-1, 0);
     }

     public movePlayerRight() {
         movePlayer(1, 0);
     }

     private movePlayer(x, y) {
         playerOne.move(playerOne.getX() + x, playerOne.getY() + y);
     }

}

GUI类:

public class ShowGUI {

     private Main main;

     public ShowGui(Main main) {
          this.main = main;
          createAndShow();
          System.out.println("GUI Successfully Loaded");
     }

     private void addActionListeners(){
          moveUp.addActionListener(new ActionListener() {
               public void actionPerformed(ActionEvent e) {
                    main.movePlayerUp();
               }
          });
          moveDown.addActionListener(new ActionListener() {
               public void actionPerformed(ActionEvent e) {
                    main.movePlayerDown();
               }
          });
          moveLeft.addActionListener(new ActionListener() {
               public void actionPerformed(ActionEvent e) {
                    main.movePlayerLeft();
               }
          });
          moveRight.addActionListener(new ActionListener() {
               public void actionPerformed(ActionEvent e) {
                    main.movePlayerRight();
               }
          });
     }         

     /* All the other methods you have */
     ...

}

因此,不使用标志(buttonPress=2),而是使用在发生特定操作时将调用的方法。同样,这不是一个完美的长期解决方案,但它有正确的要点,是你应该遵循的那种模式。