Card game, architecture for cards

3.1k views Asked by At

I am still learning the ins and outs of C#, from a Python background.

With that in mind, let's say I am making a game. For simplicity's sake, let's base it on Magic: the Gathering or any other popular collectible card game. In such a game, there are multiple cards that can be played. These cards would have different types and effects. for example, there can be a creature card, and there might be a spell card.

These types of cards have different attributes. A creature would, for example, have an attack attribute and a health attribute, while a spell might have an effect attribute. However, these different types would still be cards, and have multiple things in common, like a cost attribute. These different cards might be managed by a Manager class. A basic code sample from such a game might look like this:

public class Manager
{
    public CreatureCard card1 = new CreatureCard();
    public SpellCard card2 = new SpellCard();
}

public class Card
{
    public int cost;
}

public class CreatureCard : Card
{
    public int attack;
    public int health;
}

public class SpellCard : Card
{
    public SpellEffect effect;
}

What I basically want to do, is create cards and store them in the manager class without knowing whether they're a spell or a creature in advance. The manager class might then look like this:

public class Manager
{
    public Card card1;
    public Card card2;
}

The cards would be assigned from somewhere else.

Now, this doesn't really work. There would be no way of accessing a card's health attribute, for example. This is pretty logical, as the card might not even have a health attribute. This is why I am looking for an approach that does work, while keeping the structure about the same. So there would be a Card class, that has lotsa stuff in it, and other classes derived from it (CreatureCard, SpellCard).

Is there a way to make this work? I am coming from Python here, so this approach might actually be totally wrong in C#. If so, please tell me what kind of approach I could use instead of the one I'm trying to get to work right now.

1

There are 1 answers

5
p.s.w.g On BEST ANSWER

You can do it by casting the Card instance appropriately:

public class Manager
{
    public Card card1;
    public Card card2;
}

...
var manager = new Manager 
{
    card1 = new CreatureCard();
    card2 = new SpellCard();
}
if (manager.card1 is CreatureCard)
{
    var health = ((CreatureCard)manager.card1).Health;
    Console.WriteLine(health);
}
if (manager.card2 is SpellCard)
{
    var effect = ((SpellCard)manager.card2).effect;
    Console.WriteLine(effect);
}

Or like this:

var creatureCard = manager.card1 as CreatureCard;
var spellCard = manager.card2 as SpellCard;
if (creatureCard != null)
{
    Console.WriteLine(creatureCard.health);
}
if (spellCard != null)
{
    Console.WriteLine(spellCard.effect);
}

To expand on this:

  • To test if a card is of a specified type, use the is operator:

    bool isCardType = myCard is CardType;
    
  • Use (CardType) to cast / convert the card to the specified type:

    CardType specificCardType = (CardType)myCard;
    
  • To safely cast a card to a specific type or return null if it's not of that type, use the as operator:

    CardType specificCardType = myCard as CardType;
    if (specificCardType != null) {
        ...
    }