game design – engineering – narrative

Intro

Part of my work on the Conversational Card Game project includes systemizing the game in technical and gameplay aspects. The following is a breakdown of those efforts, including how I approached implementation using Unreal Engine’s Gameplay Ability System and ensured that designers could keep iterating with as few obstacles as possible.

Premise

The game’s tagline is “conversational blackjack.” In it, the player and their counterpart are usually players of equivalent power. They both have card decks they can play, they follow the same rules, etc.

Part of the game is that its conversations occur between the player and imaginary creatures, living concepts, eldritch gods, etc. This means that magical elements are at play, with custom cards, suits, and relationships between them.

Blackjack

To set some table stakes, this is the game structure of blackjack:

  • The game uses standard playing cards (52 cards, 4 suits, 4 special cards —  Ace, Jack, Queen, King)
  • One or more players play against a dealer
  • The players and the dealer share the two cards the dealer draws at the start of a round
  • Players bet on the outcome of each round
  • Players can:
    • Take turns
    • Choosing to hit (draw a card)
    • Choosing to stay (end their turn)
  • Dealers:
    • Deals cards
    • Chooses to hit (automatically)
  • The players and dealer share a boot (a deck)
  • Losing a hand means losing the current wager
  • Players don’t lose the game until they run out of money

Given these parameters, we get the following:

  • 2 entity types
  • 3 Object types
    • Card – Has a specific value 
    • Deck – Has a set collection of cards
    • Board – Receives cards as they’re played
  • We-go-you-go turn-based game mode
    • The dealer deals cards to players from the deck
    • The dealer deals cards to the board
    • Players hit/stay
      • The dealer deals cards on every hit 1 player at a time, left to right
    • The dealer always goes after players, dealing cards to themselves until beating the player’s hands or “breaking”
  • The players and the dealer are trying to reach a target number without exceeding that number
    • The number is not achievable with only one card
    • The number is odd
  • Players don’t interact directly. 2 possible decision points; bet, and hit/stay

The Twist

The magical element would apply on top of the standard blackjack rules, which means that the mapping I did had to account for more possible effects and relationships than what would occur in the standard game. This magic system will be developed alongside the card gameplay, so addressing specific implementations isn’t practical. Additionally, I had to account for the possibility that elements outside the card game could also come into play and that designers may try to incorporate mechanics closer to Magic The Gathering than blackjack. This emphasized the need for flexibility in the system as a whole.

Gameplay Ability System

The Gameplay Ability System provides scaffolding for gameplay interactions. However, it still needs to be structured around the intended game mechanics of a given project. The overall architecture is well-documented already, I won’t go into much detail here.

The GAS framework’s basic components are the following:

  • Entities
    • Usually denoted to have an ASC
  • Abilities
    • Target Data
    • Logic
    • Gameplay Effect references
    • Tags
  • Gameplay Effects have
    • Effect calculation
    • Logic (lightweight)
    • Tags
  • Gameplay Cues
    • Non-gameplay effects

Entities, along with attributes and tags, have abilities that they can trigger actively or passively. Those abilities have gameplay effects that they attempt to apply to targets. Those gameplay effects modify a target entity (or a group) by changing their attributes or tags. Gameplay effects can also grant new abilities to their targets, which can be used to depict a variety of complex game mechanics. These attributes, abilities, and effects are tied to the Ability System Component (ASC), which provides an Actor-based context to the other aspects I’ve listed here. Specifically, attributes are stored by the ASC, abilities are triggered and targeted in the context of an ASC, and gameplay effects apply their payloads to an ASC. Gameplay cues also refer directly to the ASC that is applying it to another ASC, or the ASC it’s being applied to, but I’m not going to delve into them here.

Something that the Gameplay Ability System doesn’t do out of the box is take into account anything that isn’t stored in an actor’s ASC. However, we can access an actor through its ASC, thereby accessing actor-based functionality.

For more information about GAS, refer to https://github.com/tranek/GASDocumentation

The Game

Cards

Cards have a type and a value. This value can be numeric, but it can also represent a glyph, in the sense that it can have other meanings — it can be part of an ordinal hierarchy, denote a calculation, etc. As such, we can consider each card to be an entity. They have attributes (their value) and tags (their type). They could then be subject to certain gameplay effects. They can also be in 4 distinct states:

  1. In a deck
  2. In a player’s hand
  3. In play on the board
  4. Discarded/In the graveyard

Each card should have an active ability a player can trigger while holding the card. They could also have other passive abilities, or be granted such abilities during play. In those cases, transitioning between those states could be used as a triggering event for those passive abilities. 

Separate from the game state the cards can exist in, they also can exist as one of two data-states:

  1. As a template. The card as it exists in a deck outside the context of being in a player’s hand.
  2. As an instance of itself. The card in the context of the game’s state and the player’s hand, with its values and effects modified by it. 

In this way, it mirrors GAS’ structure for abilities and gameplay effects. Note that this doesn’t make assumptions about anything other than cards that cards can exist in different states and contexts.

Decks

In the current conception of the game, there is only a single deck, as is the case in Blackjack. All the players, including the dealer, draw from it and discarded cards are not returned. As such, they are an ordered collection, though they are shuffled, and likely composed from cards that players and the dealer contribute. As a result, they are a part of the game’s overall state.

Players

Players have attributes, take turns, and take actions in those turns. The player’s attributes are taken as part of the effect calculations in cards that are instantiated in their context. Players also have card collections — cards they have gathered throughout the game. How those collections are leveraged through gameplay is still being developed. However, with a blackjack base, the players may choose cards to add to the shared deck, opening up different strategies where they, the dealer, or their opponent draws them. This approach allows us to theme a non-human-controlled player in ways that match their personality and furthers the ludonarrative aspect of the game, with each player using cards that match their demeanor and so on.

The Dealer

The dealer has some of the player’s capabilities. However, their behavior is dictated by the state of the game. The dealer doesn’t have their own attributes or special cards, instead act as the board’s agent. Their actions are dictated by the game’s rules instead of any strategy.

The Board

The board reflects the state of the game. While players have attributes and conditions that change how their cards behave, the board has the overall game’s state and is the context used when an effect is targeted at a player. Players, therefore, do not affect one another directly.  They have to manipulate the state of the board, taking into account the dealer, to interact with each other. 

Rounds

Rounds have distinct phases:

  1. Each player has a turn
    1. After all the players take their turns
    2. The “pending cards” are played with their effects triggering
    3. The board’s state is updated
  2. The dealer plays according to the rules, further modifying the board’s state
  3. The board’s “result” pays out, modifying the player’s attributes accordingly
  4. All the cards played during that round are moved to the “graveyard” deck

Since the dealer is just another player playing automatically, we can infer it’s drawing and staying according to the game’s rules. Its hit/stay logic is the only thing that differs from a normal player’s turn.

Win/Lose Conditions

The conditions that dictate whether a game ends, and its outcome, are the board’s and players’ attributes. The thresholds involved could vary from each game, but the overall mechanics remain the same.

Development Philosophy

Given the above gameplay scheme, and that flexibility was one of the core values that my GAS implementation needed to follow, I approached the problem with the following guidelines:

Don’t create a finished product

Rather than take blackjack and try to create a 1:1 model of it in GAS, I took each aspect of the game and broke it down further, aiming to build building blocks rather than direct, rigid solutions. The point of this work isn’t to make the game from end to end. It’s to build the components our designers will use to make it, with whatever game mechanics they create.

Data goes one way

The structure shouldn’t rely on back-references to determine the context of its effects. I learned this from working on similar game mechanic pipelines in the past. It’s better to consider the context as a shifting window where only the immediately relevant information is accessible. This will make game mechanics reusable because they are independent of the context that triggers them, which is important to make them reusable and recontextualizable. An example of this reuse/recontextualization in practice would be taking a boss’ ability and granting it to the player. This becomes significantly harder when abilities rely on references to a specific entity, and it’s often how a complex ability is implemented.

Centralize control

Two aspects of the card game we’re building dictate the structure of our game systems:

  • It’s strictly turn-based
  • We need a predictable order of operations in each turn

Given these parameters, there has to be a single source of truth about the game’s state, such as whose turn it is, the order in which abilities and effects occur, etc. Implementing things this way does add an up-front cost. This investment pays off since it will limit possible issues due to race conditions and unexpected behaviors and simplify how things are implemented later in development.

Abilities and Effects

Distilling all this structure down to a practical implementation, while also preserving the desired open-endedness of the system, boiled down to the following guidelines.

  1. Cards share logic via generic gameplay abilities that pull information from a card definition asset
  2. Card definitions are templates that are used to compose an initial deck
  3. The contents of the deck is predefined. Cards may be instanced multiple times, including during gameplay, but the deck will not receive “new” cards outside of the set of templates it had at the start of the game.
  4. An initial set of cards is instantiated at the start of the game, and their lifetime (in deck, in hand, etc.) is on a per-card state.
  5. Effects are calculated in order, with attribute calculations snapshotting their captured values whenever the effect is going to be applied.

With the player and board states being the subject of the effects being thrown around by cards, this keeps the number of ASCs to a minimum, and allows for the greatest degree of flexibility.

Assets, References and Relationships

Something I didn’t touch on here at length is the relationship that cards have with other systems like UI, VFX and animation. The game, as a conversational blackjack game, has a number of different actors that are playing specific animations, entering different states, spawning VFX and modifying UI values throughout the game. Those animations, the text of the dialogue and the UI effects that go along all of these elements are referenced through a separate relational system that goes alongside this gameplay implementation.

To present it in the most superficial way possible:

  • A editor/runtime subsystem tracks card template, animation, UI and, skelmesh model information in separate tables that have a relationship between them via unique identifiers.
  • With a pre-defined deck, we already know the full extent of all animation and skelmesh assets that could be required by an instance of the game.
  • A graph of possible conversations, including player choices, is defined by a third-party software, and imported into unreal. This graph makes references to the other asset types via the same identifiers.
  • Assets can be loaded asynchronously ahead of when they’re about to be used, once the player is locked into specific conversation paths and choices.

This system design takes into account the complexities of that four-way relationship (animation, model, dialogue, gameplay effect) by de-coupling abilities from specific cards as much as possible. This is why it’s important for gameplay abilities to be generic, since that places the emphasis on the data rather than the logic. Given that this system has to exist on both the editor and the final game client, its complexities go beyond the limits of this article.

Overall Results

With the above structure as a foundation, the project kept growing and carving itself out through multiple iterations. The final result is a complex conversational game with game mechanics overlaid on one another. Things like changes to the target number, different game states and interruptions of the regular gameplay flow were introduced, but this essential foundation remained largely unchanged. At most, it had to be extended in order to allow designers to convolute the gameplay flow so they could have specialized UI events and other specific effects.

The underlying structure didn’t change much, and designers were able to build complex implementations by using gameplay ability blueprints and gameplay effects in a way that had been prescribed before they even began. The fact that the system remains unchanged, while also supporting a wide range of iterations and development cycles is the clearest sign of its success.

Leave a comment