2017-01-18 26 views
0

我有不同的對象的情況下,工作的問題,這是發生了什麼:Java中的「Ghost實例」?

我一直在開發一個小遊戲中的Java(鞦韆& AWT)了一段時間,我有以下類別:

  • App.java
  • Play.java
  • Event.java
  • GameScene.java
  • MenuScene.java
  • Timer.java

其中:

  • 應用延伸的JFrame和是與應用程序(主)的主要功能的框架,這類創建遊戲窗口,並且只有存在此JFrame

  • MenuScene和GameScene類是應用程序的場景,例如當你看到菜單並且你想看到最高分,它是一個場景,遊戲的級別是場景等等,但是在這種情況下,我只有兩個場景和我已經在JPanels中表示了它們:MenuScene擴展了JPanel並創建了遊戲菜單(按鈕,圖像等),這同樣適用於GameScene類,這也擴展了JPanel並創建了遊戲。其他類(Play,Event,Timer)是簡單的類,它們具有「遊戲邏輯」,鍵盤控制,定時器,遊戲操作並在GameScene類的三個全局變量中實例化。

一切都與App開始,創建它的一個實例,並在構造函數中調用一個方法來「創造」菜單(MenuScene.java)。現在菜單中有一個JButton,當按下「創建」遊戲(GameScene.java)時,這個類有一個JButton隨時返回菜單......這是我遇到問題的地方,因爲如果我在玩,我返回到菜單遊戲仍然存在,我可以失去,它沒有任何意義,它就好像你玩,但不看你看到的遊戲,你看到的菜單,有趣的是,圖形部分非常好,即如果我按下按鈕,它會消除我有什麼,並迅速繪製出我想要的場景。這是因爲如果我沒有弄錯,Play,Timer和Event會在內存中實例化或「存在」。所以如果我再次按「創建遊戲」JButton,我會重新創建GameScene的第二個實例?對於MenuScene和GameScene來說,這是無限的。有針對這個的解決方法嗎?你認爲我應該如何構建應用程序?

我給你的最重要的類的輪廓:

App.java

public class App extends JFrame { 
    private JPanel rootPanel; 

    public App() { 
     //Define frame 
     ... 
     runScene(new MenuScene(this)); 
    } 

    public void runScene(JPanel scene) { 
     destroyScene(); 

     rootPanel.setBackground(scene.getBackground()); 
     rootPanel.add(scene); 
     rootPane.validate(); 
     rootPanel.repaint(); 
    } 

    private void destroyScene() { 
     rootPanel.removeAll(); 
     rootPanel.revalidate(); 
     rootPanel.repaint(); 
    } 


    public static void main(String[] args) { //Main 
     new App(); 
    } 
} 

MenuScene.java

public class MenuScene extends JPanel { 
    private App app; 

    public MenuScene(App app) { 
     this.app = app; 
     //Define JPanel 
     ... 
     buttonStart.addActionListener(new ActionListener() { 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      app.runScene(new GameScene(app)); 
     } 
     }); 
    } 
} 

GameScene.java

public class GameScene extends JPanel { 
    private App; 
    private Play; 
    private Timer; 
    private Event; //Define controls (keyboard) 

    public GameScene(App app) { 
     this.app = app; 
     //Define JPanel, Play, Timer and Event 
     ... 
     buttonBackMenu.addActionListener(new ActionListener() { 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      app.runScene(new MenuScene(app)); 
     } 
     }); 
    } 
} 

玩。java

public class Play { 
    private JLabel[][] x; 

    public Play(JLabel[][] x) { //This matrix is important (is an reference), is instanced in GameScene, this is an problem? 
     this.x = x; 
     //Define others variables 
    } 
} 

我很感激任何幫助。

+1

當你按下從比賽中復出,你應該拆除/破壞遊戲的控制,特別是定時器,你也應該取消引用程序變量,以防止任何循環引用 – MadProgrammer

+1

1)*「我給你一個大綱最重要的課程:「*爲了更快地獲得更好的幫助,請發佈[MCVE]或[簡短,獨立,正確的示例](http://www.sscce.org/)。 2)'rootPanel.removeAll(); rootPanel.revalidate(); rootPanel.repaint();'使用['CardLayout'](http://download.oracle.com/javase/8/docs/api/java/awt/CardLayout.html)如[本答案]所示( http://stackoverflow.com/a/5786005/418556)。 –

回答

0

我發現了一個有點特殊的解決方案,但我不知道這是否是最好的:

最好的辦法是,由於GC不選擇活動的定時器那麼最好是阻止他們和匹配其他對象爲null。使用要運行另一個場景Singleton模式我有一個框架的單個實例,同一實例會在任何類(場景)一起使用,在這裏實現:

App.java

public class App extends JFrame { 
     private JPanel rootPanel; 
     private static App app; 

     private App() { 
      super("x"); 
      createApp(); 
     } 

     public static App getInstance() { 
      if (app == null) { 
      app = new App(); 
      } 

      return app; 
     } 

     private void createApp() { 
     //Define JFrame, rootPanel, buttons, etc ... 
     } 

     public void runScene(JPanel scene) { 
      rootPanel.removeAll(); 

      rootPanel.add(scene); 
      rootPanel.revalidate(); 
      rootPanel.repaint(); 
     } 

     public static void main(String[] args) { //Main 
      getInstance().runScene(new MenuScene()); 
     } 
    } 

GameScene.java

public class GameScene extends JPanel { 

    private Play p; 
    private Timer t; 
    private Event e; //Define controls (keyboard) 
    private JLabel[][] mat; 

    public GameScene() { 
     //Define JPanel, Matrix, Play, Timer and Event 
     ... 
     buttonBackMenu.addActionListener(new ActionListener() { 
     @Override 
     public void actionPerformed(ActionEvent x) { 
      This method is useful to create another scene for example from another instance other than this (GameScene) 
      changeScene(new MenuScene()); 
     } 
     }); 
    } 

    public void changeScene(JPanel scene) { 
     e.removeKeyDispatcher(); //You must create a method that allows you to move the event key dispatcher 
     t.stopAllTimers(); //You must create a method to stop all timers, or any object that is active. 
     t = null; 
     e = null; 
     p = null; 
     //If you have more active objects and work with other instances of other classes they should be "broken" or "stopped" and then match their instance to null 
     App.getInstance().runScene(scene); 
    } 

    //Optional... 
    public JLabel[][] getMat() { 
     return mat; 
    } 
} 

Play.java,Event.java,Timer.java(X)

public class X { 

    private GameScene g; 
    private JLabel[][] mat; 

    public X(GameScene g) { 
     this.g = g; 
     //I would use the instance of the class I need to access the variables I'm going to use, for example: 
     this.mat = g.getMat(); 
    } 
}