It's just a Phase - Duh
Hello, and Servus
Welcome to our Devblog, where we share information about the creation of the Mulatschak Game App, as well as its companion app.
Today we will focus on the core logic behind the game, how it evolved, and how abstraction brings value to a turn- and phase-based card game.
The initial concept
When first starting off with the project, the initial idea was to create a GameManager.
This GameManager was intended to fully hold the game's internal values, as well as managing ALL the logic. At the time, this sounded like a splendid idea. To manage the different phases of the game, a GamePhase enum was created, to branch the logic depending on the current phase.
As the first (and currently only) version of the game is played against AI enemies, we decided that a BaseController type would be useful, with HumanController and AIController as child classes. BaseController implements virtual and abstract functions, that are implemented and overridden by the concrete Controllers. An early version of this concept can be seen in this image.
The friends, and changes, we made along the way
As the attentive reader might have already guessed, using enums in a switch to branch logic for different phases was not a very scaleable idea.
Therefore, the idea of the GameManager was abandoned, and two new Managers were introduced, the RoundManager and the CardManager.
The RoundManager keeps track of the state of the current round and can be seen as a high-level manager.
It manages the overarching structure of the game and instructs other parts of the code.
The manager tracks the following metrics:
- Participating controller and their special roles (dealer, currently active controller, declarer, ...)
- Called Trick and Suit
- Won Trick
- Played Card
Instead of using enums to structure the game flow, every game phase was implemented having their own functions.
The available phases are:
- Dealer selection (only done before the first round of a new session)
- Trick Calling
- Suit Calling
- Exchanging Cards (also decides whether a player does not want to participate in this round)
- Playing Cards
These phases are traversed every round, dealer selection excluded.
In the trick calling phase, the option "Pass" eliminates the player from being able to participate in trick calling. The players take turns calling until every player but one has called pass. The non passing player becomes the declarer of the round, and may call the suit for this round.
Then, the declarer begins exchanging cards. When they finished, the exchanging is continued clock-wise.
When everyone exchanged, the declarer begins the first of 5 playing rounds, also played clockwise.
CardManager
With the RoundManager being the high-level manager, that instructs the code WHAT to do, the CardManager is responsible for HOW we do what needs to be done.
The CardManager is responsible for every type of card manipulation:
- Deck population
- Card dealing and drawing
- Card playing
- Legality checks of cards that are trying to be played
- Visual manipulation of playing cards
The Controllers
The concept of a BaseController that is extended by concrete Controller types has been kept.
Similar to the phases in the RoundManager, the controllers also have their respective phases in which they execute different pieces of code.
The HumanController mostly differs from the BaseController in the handling of UI elements as input parameters.
The AIController does not need these, as its decisions are made by one of two different AI behaviors that mimic the inputs of a human.
The actions available to the controllers are fully determined by the Managers to avoid permitting illegal actions.
This was done with foresight to a later multiplayer addition with an authoritative server.
Takeaways
So what exactly did we learn on our journey through the cards?
First of all, managing a phase based game seemed much simpler in the beginning, as we underestimated the dependencies between the phases and the possible edge-cases that arose (also due to some poorly formulated requirements).
The complexity of the game Mulatschak with its special cases, like real time actions with Unterm Hund an Muli!, round redoing when everyone passes, cutting cards, different discard and drawing stacks depending on who discarded how many cards, potentially also changing the exchange order, and the most important of all, THAT DAMN WELI CARD!
What seems easy when understanding the rules as a human, is sometimes quite difficult to put into code.
For everyone intending to create a complex card game, we recommend to write done every detail to the fullest before touching any kind of code editor, as changing existing code in this intertwined setting often caused more harm than good.
Stay posted for our next updates on how to deploy an App to the Google Playstore and the iOS Appstore
Yours, Jonas
Mulatschak
Status | Released |
Authors | Noobesch, MedusaFaun968 |
Genre | Card Game |
Tags | austrian-classic, Casual, Singleplayer |
Leave a comment
Log in with itch.io to leave a comment.