0
\$\begingroup\$

I'm developing an italian card game using the mvc pattern. I have the class GameFrame that contains the view. The user's card are buttons (JButton objects). I have 3 controllers:

  1. GameController: to control the game in general. Contains the game loop.
  2. HumanPlayerController: to control the user input
  3. ComputerPlayerController: contains the AI of the computer
  4. PlayerController: is an interface with the makeTurn() method. It's implemented by HumanP.C. and ComputerP.C.

HumanPlayerController implements ActionListener too. But what is the right way to access to the GameFrame buttons? I need it for understand which card was chosen.

GameFrame and HumanPlayerController are in different packages. Should i make the JButtons public?

\$\endgroup\$
1
\$\begingroup\$

The way I've done this is by defining an interface to the GUI elements that controllers want access from the view.

public interface GameFrameView {
    public JButton getCard();

        // Any other gui elements
}

And then my view classes would implement this interface

public class GameFrame extends JPanel implements GameFrameView {
    private JButton card;

    // Everything else about this view...

    @Override
    public JButton getCard() {
        return card;
    }
}

And then my controller classes would only have reference to the view classes through the interface (in this case, GameFrameView), which I normally fulfill via dependency injection. This way, the two are decoupled and you can change either without disrupting the other (as long as the interface doesn't change, or course).

public class HumanPlayerController {
    private GameFrameView gameFrameView;

    // Notice that I'm passing in reference by the interface type, not the concrete view type that implements the interface.
    public HumanPlayerController(GameFrameView gameFrameView) {
        this.gameFrameView = gameFrameView;
    }

    public void addCardButtonListener() {
        gameFrameView.getCard().addActionListener(new ActionListener()/*etc*/);
    }
}
\$\endgroup\$
0
\$\begingroup\$

Edit: My original answer did not really follow MVC, sorry for the confusion. If you look at http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller then you will see that controllers don't listen to models. So for the cases where you don't have a user involved, you either don't use MVC pattern or you replace the user by some Logic Class.

My updated design (pseudocode):

GameTable
  List<card> visible
  List<card> deck

  changeDeck(...) { notify_observers(Event.deck_changed) }
  changeCardOnTable(...) { notify_observers(Event.visible_cards_changed) }


GameState    
  List<card> selectedCards[num_players]
  boolean gameOverManGameOver;
  int     turn

  startGame(...) { notify_observers(Event.game_started) }
  checkWin(...)  { notify_observers(Event.game_won_or_lost_etc) }
  playerChooseCard(player, card, ...) { notify_observers(Event.player_chose_card) }
  endTurn(...)   { // Do some calculations and some events }

AI Manager (you probably don't want to use a controller, because you have no view or user, so essentially you are merging 3 functionalities into one class, it is no longer MVC, but something different.

AI Manager
   SomeStrategyClass strategy;

   init(GameTable tableModel, GameState stateModel) {
      observe(tableModel)
      observe(stateModel)
   }

   onPlayerEvent(...) { 
      stragegy.think(tableModel, stateModel);
      stateModel.playerChooseCard(strategy.whatToDoNext());
   }

   onInitOrWinEvent(...) {
      // Reset/start/whatever AI should simulate on this event, etc
   }

You don't really need a game controller, all the logic on how to play the game, should go inside your models, most likely your state model, inside nextTurn() function. Which leaves you with the remaining View and Controller

Player Controller
   GameState stateModel;

   chooseCard(...)         { stateModel.playerChooseCard(...); }
   resetGame(...)          { stateModel.startGame(); }
   doAction(...)           { // do something with one of your models }

Player View
   init(GameTable tableModel, GameState stateModel) {
      observe(tableModel)
      observe(stateModel)
   }
   abstract onCardChangeEvent(...);
   abstract onGameWinOrLoseEvent(...);
   abstract etcEvent(...);

Your JFRAME will have a combination of various gui elements, so when you build it it might be something like this.

 GUIFrame extends PlayerView
    Button resetButton;
    PlayerController controller;

    // Link button to controller
    init() {
       resetButton.addListener( controller.resetGame() )
       someOtherButton.addListener( controller.doAction() )
    }

    // Implement view methods
    onCardChangeEvent(...) { // redraw gui to show new card layout }
    onGameWinOrLoseEvent(...) { // display some text that the player won or lost }
    etcEvent(...) { // change the GUI to react to change in model state

I hope I didn't make the answer more confusing. Cheers.

\$\endgroup\$
  • \$\begingroup\$ Thanks for your answer. In the MVC the View implements Observer and the model/s extend Observable, right? So, if the GameController must receives events from GameState, it should extend Observer too? Is that right? For the GameState maybe i should implement the pattern State? (A class for every possible state). I need a little example for GameState, plase :c. However, i don't understand how i should listen the user input yet. \$\endgroup\$ – Loris Jun 5 '14 at 18:36
  • \$\begingroup\$ I would refer to the diagram in the wikipedia as your starting point of design. I was wrong originally, because controllers don't really listen to model events at least not in the MVC pattern. To make different components talk to each other you either need an observer pattern or some sort of Event mechanism so that each component can talk to one another. \$\endgroup\$ – Vitaly Omelchenko Jun 5 '14 at 20:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.