Search code examples
javaswingmodel-view-controllergui-builder

Can you build a Swing GUI for an MVC-style game if the Controller doesn't have a reference to the Model?


I couldn't find any similar answers on here, but apologies if this it too specific to my own problem.

I am building a simple game using in Java that has both a command line interface and a GUI (activated using a command line flag). The way that the game is written is that the game logic (Model) has a reference to the input (Controller) and the output (View), but neither the input or output have a reference to the model (this was a requirement). The flow of the game is therefore controlled by a loop in the application model similar to:

while (!gameFinished) {
    InputType in = input.getUserInput(); //1
    performAction(in);
}

Now that I am trying to build a Swing GUI for this (not something I have experience in), I am struggling to see how it could work with event listening. It would ideally work in the way that when a button is pressed (new game, save game, exit game etc.), an InputType would be sent to the Model (essentially doing the same that the commented line does) to be handled accordingly. But if it doesn't hold a reference to the Model, it can't 'send' the InputType. I suppose I am looking to build a GUI that works with the Model 'asking' for input, rather than 'listening' for it.

Is this possible? And if so, can anyone provide me with any useful resources for solving this? If not, an explanation or potential alternative solution suggestion would be appreciated.


Solution

  • I'm not gonna go into whether your flow is right or wrong.

    • Create an event queue in input. Listeners can then add events to the queue. Model can then ask the Input whether there are unhandled events in the queue and perform an action depending on the event that occurred. Let model hold a reference to the view interface call the appropriate view method in the performAction method.

    Pseudo code:

        class Controller{
        Queue<UIEvent> events;
    
        void setupUI(){
            button.addEventListener( new EventListener(){
                 Model.this.events.add(new TappedButtonEvent());
            });
        }
    
        UIEvent dequeueEvent(){
            if(events.size() > 0){
                return events.pop()
            }
            return null;
        }
    
        }
    
        class Model{
    
        public void loop(){
            while (!gameFinished) {
                 UIEvent in = input.dequeueEvent();
                 if(in != null){
                      performAction(in);
                 }
            }
        }
        }
    
    • Do not encapsulate how something is displayed in Model, let view handle it.

      interface View{
      void displayExitMessage()
      }
      
      class CommandLineView implements View{
      
      void displayExitMessage(){
          this.commandLine.append("Are you sure you want to exit(Y/N)?");
      }
      }
      
      class CommandLineView implements View{
      
      void displayExitMessage(){
          this.window.showDialog("Are you sure you want to exit?", Button.YES, Button.NO);
      }
      }