2
\$\begingroup\$

We are working on a simple turn-based card game. We would like to implement it using a design which let us create additional "monsters" and "events" later on (so the code should be flexible).

Also, we would like to separate the actual logic (who does what) from the presentation (view/rendering) so we could write a different renderer whenever we want (Unity, WPF, etc.)

This game is already playable on paper (we have a table, figures, cards, etc.) but we would like to speed up some things (for example the battle). And this would be a learning project. This is the reason why we would like to implement it in a nice way (instead of just "hacking" things together).

The main concept of the MVC pattern is to have the model, controller and view separated. In a fully-separated design the view can display the model by asking the controller to give some data. The view can also ask the controller to modify the model based on its input. However the controller has no knowledge about the view.

Our problem is that we would like to "generate the view" based on the "controller" (action). This might sound a little wierd but let me give you some examples:

In this game we have some special "event cards" and these are doing different things when the player meets with them. For example the "Wise" gives the player x gold based on a roll OR it gives the player his treasure if he has any. Since we are not storing the actual map in this program (we are playing on a physical table) the GM (Game Master) must choose the operation based on the current state of the game. This means that when the GM selects the "Wise" there should be two buttons, like "Give treasure" and "Give gold". This is when the controller/model/action defines the view.

Something like this:

  1. GM selects the player
  2. The player makes some action in real-life
  3. When the player enters a zone where an "event card" can be found, the GM selects the right "event card" on his tablet (for example)
  4. Then the selected event card defines the possible actions which defines the view (since the GM has to press some buttons)

It is not important that if we are generating the view (using a layout and filling it with text and buttons) or if we are creating the views by hand. The main problem is that we don't know how to "glue" them together. When the GM selects an event card, which view should we generate? Which button should execute which action? Sometimes a specific action requires another view to be shown. This seems like a hard coupling between the logic and the view.

Here is a mini code-snippet (note this is not the actual code, it's just an example).

interface IEventCard
{
    void Selected();
}

class Wise : IEventCard
{
    void Selected()
    {
        // add "Give treasure" action
        // add "Give gold" action
    }
}

class GameManager
{
    IList<IEventCard> cards;

    void Initialize()
    {
        // create cards
        cards = new List<IEventCard>();
        cards.Add(new Wise());
        // ...
    }

    // called from the UI
    void Select(int id)
    {
        IEventCard card = cards[id];
        card.Selected();

        // it should open a view
        // the view should be populated with:
        // - the name and description of the event card
        // - buttons that execute the corresponding action
        // some of these actions should open another views
        // for example the "give treasure" action should open the "inventory screen" which lets the GM select the item
        // or the "give gold" action should open a "roll the dice" window first to determine how much gold the player should get
        // etc.
    }
}

Sorry if it's hard to understand my description, I've tried to explain things as short as possible. We would appreciate if you could give us some tips, preferable some code snippets.

\$\endgroup\$
  • 1
    \$\begingroup\$ I would advise you to move focus away from separating "logic" from "view". Instead focus on separating the game/domain logic from the view logic. The game logic should not need to know about the viewlogic, but the view logic knows about the game. If an action should change the view, this is entirely view logic and we should not need to tell the game logic about it. If something happens in the game logic that should trigger something in the view, you should use events, messages or polymorphism. \$\endgroup\$ – David Aug 2 '17 at 13:07
  • 1
    \$\begingroup\$ Also, everyone likes Uncle Bob: youtu.be/Nsjsiz2A9mg?t=31m44s \$\endgroup\$ – David Aug 2 '17 at 13:21
  • \$\begingroup\$ It sounds like an MVVM pattern where the ViewModel is basically the "view logic" you have mentioned. The harder part is when the logic triggers something in the view. Or not something IN the view but ANOTHER view. Another example is the battle with special monsters. The battle is basically a turn-based roll-the-dice battle (the higher value wins the trade and damages the other). However there are some special monsters that have to do some special actions based on different conditions. For example the player must roll the dice ("try its luck") if the Vampire rolls double 5 \$\endgroup\$ – csisy Aug 2 '17 at 13:44
  • \$\begingroup\$ Well you could also use the model view presenter, where the presenter is concidered view logic and contains all code that generates the view. The importance is to sepearate the view code from the game code. If a view need to talk to another view thats fine. Either use a simple reference. Or if what should change concerns the model (game logic) aswell: change the model and let them talk indirectly by subscribing to model changes/events that happen in the game code. \$\endgroup\$ – David Aug 2 '17 at 13:53
1
\$\begingroup\$

I think the problem here is that your model is too simple. You are correct in that the controller should get all the required details for the view however your example only shows what the card should do once it is selected.

I think that your IEventCard should implement a method for the button amount, the button text and the card text which should help generate the view.

To make it more friendly in the future you could also add a heuristic to the card which makes it trigger when it is most appropriate. That way your controller knows nothing about the actual cards and just selects the appropriate action. If I implemented this I would have a method like EventLikelyHood which I would call when an event card is needed I would then pass all the possible things that affect what card should be picked as parameters or even better as a structure that contains all the variables (so that you don't have to amend existing cards everyone you need to add something). So say your players enter an event zone the controller would cycle though all cards and get a number for the likelihood that the event would happen and store them or keep a record of which card currently has the highest chance. When all cards have been tested you execute the highest card.

Now you have all the details needed for the UI the controller only knows about the cards and not the data and your view only has relative information.

\$\endgroup\$

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.