0
\$\begingroup\$

I'm making a card game right now and I am hesitating in how to design my cards.

Let me explain

I have a card that draws two cards from the deck when played. The way I'd code it is I'll create a class called Card where I'll put all the info a card could have (cost, description, name, etc). Then I'll create another class that'll inherit from Card and add a method to it which draws two cards, so when played, I'll call the method.

If the game gets bigger, would this be easily manageable and efficient?

Or how should I approach this instead?

\$\endgroup\$
1

1 Answer 1

0
\$\begingroup\$

Considerations

I have a couple of considerations for this architecture

Cards with Multiple Effects

Right now, you have a card that when played, draws two cards. In the future, you might want a card that draws 3 cards and then discards 1, or a card that discards 1 and then draws 3.

A good architecture will allow you to re-use code between cards with similar effects.

Cards which trigger other than when played

In a more complicated game, you might have a card that says, "When you draw this card, take two damage."

A good architecture will support weird cards like this.

Solution: Events

If you are working in C# (like with Unity), there is an elegant language feature that can help here called Events.

Each event can take an arbitrary number of subscribers, and fires all of them in order when those events are triggered.

Here is some example code.

public delegate void CardEffect(CardPlayer player, CardGameObject? target);

public class Card
{
    public event CardEffect Played;

    public event CardEffect Drawn;

    public event CardEffect Discarded;

    // TODO: Write some code here to invoke the events when they come up.
}

public static class ExampleCards
{
    public static Card DrawTwo()
    {
        var card = new Card();
        card.Played += ExampleCardEffects.Draw(2);
        return card;
    }

    public static Card DrawThreeDiscardOne()
    {
        var card = new Card();
        card.Played += ExampleCardEffects.Draw(3);
        card.Played += ExampleCardEffects.Discard(1);
        return card;
    }

    public static Card TakeDamageWhenDrawn()
    {
        var card = new Card();
        card.Drawn += ExampleCardEffects.TakeDamage(2);
        return card;
    }
}

public static class ExampleCardEffects
{
    public static CardEffect Draw(int amount)
    {
        return (player, target) => player.Draw(amount);
    }

    public static CardEffect Discard(int amount)
    {
        return (player, target) => player.Discard(amount);
    }

    public static CardEffect DealDamage(int amount)
    {
        return (player, target) => player.DealDamage(target, amount);
    }

    public static CardEffect TakeDamage(int amount)
    {
        return (player, target) => player.DealDamage(player, amount);
    }
}

```
\$\endgroup\$
3
  • \$\begingroup\$ Throwing in a member for each hook gets ugly if your card rules become more complicated. This gets a bit unwieldy when you have cards that add CardEffects to other cards or when you realize you need more triggers (e.g., "do X if you take 5 damage with this card in your hand" or, "do X at the start of the game"). \$\endgroup\$
    – Brian
    Nov 4, 2022 at 14:07
  • \$\begingroup\$ First, thanks for your answer Tim, second i'm a newbie, third what do you exactly mean by invoke the events when they come up? \$\endgroup\$ Nov 6, 2022 at 17:22
  • \$\begingroup\$ @younesalaoui - When the card is drawn, you would need to have the card call this.Drawn?.Invoke(). That will cause every method that has been "added" to the Drawn event to be triggered, in order. \$\endgroup\$
    – Tim C
    Nov 6, 2022 at 18:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .