XNA Creators Club Online
Page 1 of 1 (6 items)
Sort Posts: Previous Next

Need help with a Collectible Card Game (CCG)

Last post 11/20/2009 4:07 AM by jwatte. 5 replies.
  • 11/19/2009 3:15 AM

    Need help with a Collectible Card Game (CCG)

    I'm making a CCG and I'm not sure what would be the smartest design when it comes to the powers on the cards.  I have a Player class that has access to all in-game objects.  I also have a Card class that is only aware of itself.  Cards have powers or effects that can affect other objects but I don't want to have to pass in a ton of objects to each Card.  I'd like for the Player class to actually do the 'heavy lifting' and the Card class can remain simple and dumb.  If each card had a string consisting of C# code that the Player class could read and execute then that'd be perfect.  Or, if each Card could just have a block of code that the Player would execute...

    For an example of some cards, a 'Knight' card might do damage to an opponent player.  A 'Buff' card might boost the attack power of another card.  A 'Crystal Ball' card might allow a player to view another player's hand.

    I was thinking, maybe I could use the Command design pattern and have the Card class pass a Command object to the Player and the Player (with its widespread access) could then execute the Command?  Or, should I set the Player class as a Singleton so that each card can access the Player's members?  Or, should I just pass every in-game object into the Card and have widespread entanglement and ugly-but-working code?  Basically, I don't want each Card to have global awareness.

    Thanks in advance.
  • 11/19/2009 4:25 AM In reply to

    Re: Need help with a Collectible Card Game (CCG)

    I think you might want to sit down and decide what every action is that a card can do.  And then think about how they relate and group together.  Get yourself a pure abstraction of a cards function.

    So, start with the basics that every card has.  If your game has resources, then every card has a resource cost, even if some of them have a cost of 0.  Every card can probably do damage, even if it is zero (healing can be negative damage).  And on and on.  And then every card uses all of these values in execution.  Since the ones that don't cost anything or don't do damage will have zeros for values, they will have no affect on gameplay if you apply the cost or damage.

    If it comes down to cards haveing obvious groupings where the information differs, then you can look into restructureing with a few interfaces.  For instance, a unit or creature card of some kind will have things like hitpoints that other cards do not.  Item cards might have slot or class restrictions that other cards do not.  Spell cards may have mana costs, etc.  So, you can design Interfaces for Unit, Item and Spell cards and then all cards can implement the common interfaces for execution.  This type of grouping can also be helpful, because most ccgs that I have played have restrictions on when certain cards can be played during gameplay. 

    The abstraction part is going to be the difficult and most useful part, though.  If you had, say, 300 cards in your game, you certainly wouldn't want to hand code every one of them and try to test the multitude of ways they can combine.  Especially, since the difference between something like an orc card and a large orc card might only be different hitpoint and damage values.  You would want to have a single definition that encompasses all of these traits.  Then, the only hand coding you have to do is tweaking a settings file or something.
  • 11/19/2009 5:19 AM In reply to

    Re: Need help with a Collectible Card Game (CCG)

    Looking some more at your post, I see some of it was directed towards how to get all the information passed around.  I can tell you how I would do it.

    First, you seem to be trying to limit yourself to player and card classes.  However, that isn't all that in play with an OO design.  The player class is going to be interested in cards, but only the cards it has.  It won't care about the opponents cards (although the opponent will be a player class as well that only cares about its cards).  The cards will only care about themselves and their target.  They don't need to know about any of the other cards out there.  So, if I am only concerned with my cards, how can I interact with the other player and his/her cards?  You are missing a larger piece of the OO puzzle.

    I would have some type of game manager class that controls the flow of the game.  It would be like a dungeon master in a D&D game, not really part of the game, but it knows and controls all.  The base XNA Game class is actually the ideal class for it, imo.  It even has a good name.  From an OO perspective, the game class would be concerned with the players and the cards on the field.  Speaking of cards on the field, there would be another object that would be the game field.  This class would have all of the cards in play and would be passed to each player on its turn.

    My game flow would be something like this:

    1. Game decides it is Player X's turn and initiates code to notify player X's class to execute its turn.  This also passes in the game board, which contains all of the current game state information.
    2. Player X's class has his deck and hand cards.  At the start of his turn, he draws a card from the deck and places it in his hand.
    3. The game board class knows all of the cards currently in play.  The players are also considered to be in play, so it has a reference to each player as well.  So, Player X is able to get some information about Player Y to help decide his/her move.  Information like how many cards are currently in the player's hand or how many hitpoints they have.  Using all of this information, the player class makes moves.
    4. Player X decides to play a unit card to the field.  No matter how the UI decides that the player is taking this action, the player class queries the card for it's resource cost and target type.  If the cost is less than or equal to the player's current resources, then the card can be played so far.  Next is to check the target type.  The target type for a unit might be "Empty Field Slot".  So, the player class verifies that the user is trying to place the card in a empty field slot.  If it is, then the card be played.  If either condition fails, the card is not played and the user is notified.
    5. To play the card, the card's interface is called to execute with its target (Card.Play(cardTarget)).  And, the player class removes the card from the player's hand collection.  In this case, the implementation for a unit card execution is to simply attach itself to the field slot object.  Now the card is a part of the playing field.
    6. Player X decides to attack Player Y with the unit.  Once again, the player class verifies that any conditions that are need are met, like not being blocked.
    7. The player class notifies the unit card of the attack execution and passes it the target of Player Y (Card.Attack(playerY)), which would likely be a part of the Unit interface definition.  The card's method in this case simply reduces the player's hitpoints by the damage value of the card.
    8. Player X decides he/she is done with their turn.  The player class notifies the Game class that it is done.  This can be simply the player class leaving its ExecuteTurn() function.
    9. The Game class queries Player X and Player Y and asks if either one has lost the game.  If not, then it tells Player Y to execute its turn. 

    And the game would go on like this.  Everytime a player finishes their turn, the game class looks for a loser (in CCGs, you usually win by making the other player lose, like killing them.  This is different then in a game like Tic-Tac-Toe where you win by completing a task.  With those kind of games, the overall game class would look for winners, not losers.)  If there are no losers, then it tells the next player to take their turn.  If you want to have game situations where there are back and forth response type gameplay, like combat, then you would have to redesign a bit and reduce 'turn' to 'move'.  Then each player gives up control after each move and the game class makes the decision on who's move it is next, even if it is continually the same player.  The game class would have to keep track of important events to help decide who is next.
  • 11/19/2009 2:57 PM In reply to

    Re: Need help with a Collectible Card Game (CCG)

    Thanks for your help.  It sounds like you would have the Player class pass in the relevant object and the Card would apply it's effect to that object.  So if the card deals damage to an opponent, you pass the opponent into the call to the Card.  If a card destroys a mana or land card, you pass in the mana or land.  That makes sense.
  • 11/19/2009 4:30 PM In reply to

    Re: Need help with a Collectible Card Game (CCG)

    I have designed several CCG's and let me tell you that it is no easy feat to design one, let alone computerize it. Be prepared to test a near infinite number of scenarios depending on how the cards can interact with each other. Obviously, I cannot comment on the specifics of your game mechanics without seeing a complete list of cards or rule set, but I can comment on how I would initially look at implementing a "generic" card game with interacts similar to Magic, L5R, etc.

    First, the state of the game is probably the most important aspect you will be dealing with. You should look into the "blackboard" design pattern for your information handling. This will let you have a global list of "targets" as well as a single point of lookup for game stats such as player life totals. Within your "blackboard," you could organize cards into your typical game configuration (player decks, player hands, player boards, etc.) and add appropriate shortcut queries as desired. There is a bit more to this, but again, it depends on what your game can do.

    Regarding the actual functionality of the cards, it is going to be a bit more difficult to implement. You are going to have to analyze your game for every possible ability that a card can have and translate that into your game functions. For example, a "Remove target creature from the game" type function may have an obvious implementation, but a "Remove target creature with a power less than 2 from the game" function is less obvious. In the former, you simply have to make the creature go away, but the later requires you to verify that the creature fits the parameters of the function. Having said that, here are some tips for creating the functionality of cards (pseudo-code used as appropriate):

    • Use a {keyword; parameter1, parameter2, parameterN} type approach to card functions. Verify that a card meets the parameters of a function before applying the function. Better yet, use the parameters to filter the list of "targets" that the player can select before even trying to use the card.
    • For complex cards, use an ordered list of functions to define their end functionality. Example: "Discard a land card from your hand to remove a creature with toughness greater than 2 from the game" could translate into two actions. The first action would be {"DISCARD"; "Type==LAND"}. Once this action is done, then the {"REMOVE"; "Type==CREATURE", "Toughness>2"} action can take place. Ordering is very important for the user interface aspect here, as choosing the creature before discarding the card would not be logical.
    • For the individual functions, try to distill each card into easily digestible parts with simple functions. This will make it easier to both implement the game, as well as tweak the parameters of cards for balancing purposes.
    • If you really need to support complex single functions, consider the use of scripting.


  • 11/20/2009 4:07 AM In reply to

    Re: Need help with a Collectible Card Game (CCG)

    There are two ways to go I know of.

    1) Cards can be dumb data, and there's a "rules" engine which resolves the action of cards. This works as long as cards are mostly regular. Regular 52-card decks work super with this model.

    2) Cards are active objects, with "resolve" functions written in C#. This is where you'd end up if your game was complex like Magic:TG or Yu-Gi-Oh.

    Take M:TG as an example, the player can do a few things to cards: tap cards for effects, untap cards, pay mana for effects (only some cards), declare attackers, declare defenders, add or remove counters, discard cards, bring cards into play, etc.
    Play is always done in some context -- whose turn is it, what level of play (upkeep, sorcery, immediate, interrupt, etc), who is the playing player, controlling player, owning player, target player, creatures, etc.
    For M:TG, you'll also need some additional state. When a player declares attack, that puts state into a separate attack resolution phase; after that's done, you go back to the sorcery phase if memory serves. Because you decare all your attacks at once, this means that "the set of declared attack creatures" is state that's part of the resolution, not part of the card.

    So what do you do with a card like "Millstone: (T), (2)(1): Force target player to put top two cards from library into graveyard." (am I dating myself here? :-) This card has an effect that has a cost, and requires it to be un-tapped. You could either declare the cost and requirements on the card (needs tapping, costs 2+1), or you could have a "CanEffect()" function where the card itself would figure out whether it could be played. I would probably do the latter. If the player decides to go ahead and DoEffect(), the cost would actually be paid, and the effect would be carried out. Note that the doing of the action still may need additional information, both because it requires a target, and because other players may come in with instants and interrupts.

    But it gets better! Enchantments can change cards! Thus, you really need each stat (mana cost, damage, strength, color, etc) to be a list of affectors. That way, for example, you may have one enchantment which turns a red creature black, and another creature which gives each black creature the Wither capability. The second creature would have to listen in to the play area for the current player, so that each new card played (or updated) could be appropriately modified; it would also have to un-modify them when destroyed, sacrificed or removed from play. Other cards do things when players take damage, or when players tap lands for mana, or disallow un-tapping of cards, etc etc etc.

    In the end, you need a variation point for each possible action in the game, and you need a variation point for each possible card and player statistic/property, and you need the ability for cards and actions to modify what those are for other cards.

    Finally, the "resolver" (that takes care of turn, phase, order of play etc) might want to be structured on an "event" basis. This lets cards/effects listen in on the "resolution effect" of an action, and modify that, in turn, as appropriate. (Consider a card that says "this card doubles damage dealt to green creaturs this turn" for example)

    Making everything hookable is not that hard. Defining all the possible statistics and action points is only a little harder, and very dependent on game design. Writing a resolution system that allows for targeting, re-targeting, cancellation, undo etc is hard. Writing a UI that allows the player to easily see what moves are allowed, and not allowed, is quite hard.

    Trying to make cards be only dumb containers of data is only really useful for card games like Uno, Bridge or Poker. I'd suggest adding code to specific cards for anything more complex. And, because you need to write the code anyway, you might as well write it into the card, rather than into some script from whence you'd compile and execute it. (Also, System.Reflection.Emit and the CSharpCompiler are not available on Xbox)
    To help building cards, you could also define standard "actions" (pay mana, tap card, etc) and standard "effects" (deal damage, block damage, etc), and attach them as appropriate to the cards in question using composition, rather than inheritance -- I think interfaces are great for cards, but inheritance would be way too restrictive.

    Well, that's as far as I can type for now. Hope this helps!
    Jon Watte, Direct3D MVP
    Tweets, occasionally
    kW X-port 3ds Max .X exporter
    kW Animation source code
Page 1 of 1 (6 items) Previous Next