1
\$\begingroup\$

I've been trying to program a video game adaptation of the popular trading card game "Magic: The Gathering". If you've played MTG before, you'll know most cards have an effect, which is activated at a certain time, usually when it's played. But I'm unsure how to implement effects into my game.

I'm thinking of creating a method that assigns a card its effect when it's played based on the card's name, but that doesn't really work when a card's effect isn't supposed to be activated when it's played, like in the case of Deathrattle cards, or when it's a continuous effect. I've thought of creating a thread for each effect which activates it whenever needed, but... that's a LOT of unique threads. I haven't found any similar java programs anywhere, so I wanna ask here. How do you think card effects should be handled?

\$\endgroup\$
4
  • 2
    \$\begingroup\$ Possible duplicate of Design of a turn-based game where actions have side-effects \$\endgroup\$
    – Philipp
    Jun 1, 2016 at 14:30
  • \$\begingroup\$ Please try to make titles specific to the question. Don't include code if you don't need it, in this case, a high level question like this shouldn't need code. Further, it's not clear what kind of effects you're talking about. Visual effects? Something else? \$\endgroup\$
    – House
    Jun 1, 2016 at 14:32
  • \$\begingroup\$ Definitely do not use threads for this. \$\endgroup\$
    – Philipp
    Jun 1, 2016 at 14:35
  • \$\begingroup\$ Somewhat related: Ability/Skill Data and Method Structure (C#, Unity3D) - not clear from the title, but the question is about cards with various game play effects. While that question doesn't cover threading per say, it does cover some general design. \$\endgroup\$
    – Pikalek
    Jun 1, 2016 at 15:23

2 Answers 2

1
\$\begingroup\$

Threads would definitely be overkill here. I would use event listeners.

First, make an ICommand interface. (The param is so that you can optionally pass data to your command)

public interface ICommand{
    public void execute(Object param);
}

Then make sure you clearly define every scenario in which a card will activate and create a ICommand variable in your Card class essentially creating a "slot" for each event type.

//Card class
ICommand onDeathrattleCommand;
ICommand onCardPlayedCommand;
//... other event types

When you create each card type, you initialize the appropriate event slots

Card deathrattleCard = new Card();
deathrattleCard.onDeathrattleCommand= new ICommand(){
   public void execute(Object param){
       foreach(Card opponentCard: opponentsCards){
           opponentCard.applyDamage(6);
       }
   }
};

Then trigger these events at the appropriate time

//Card class
public void onPlayed()
{
    if(onCardPlayedCommand != null){
       onCardPlayedCommand.execute(null);
    }
}

public void applyDamage(int damage)
{
   hp -= damage;
   if(hp <= 0 && onDeathrattleCommand != null){
     onDeathrattleCommand.execute(null);
   }
}
\$\endgroup\$
1
  • \$\begingroup\$ An event based solution was recommend to me for a turn based game (also in Java) using table top / card based mechanics. In my case, I also needed to ensure repeatable outcomes which would have added a lot of extra complexity to a thread based solution. \$\endgroup\$
    – Pikalek
    Jun 1, 2016 at 17:58
0
\$\begingroup\$

The representation of game state should be the core of your architecture, because it ties everything else together. Player actions, the sequence of events in a turn, card effects are strictly layered on top of game state.

For example, you can have an index of triggered abilities by the type of event that triggers them, and when anything happens you could

  1. Enumerate all relevant triggered abilities for the event (e.g. a permanent enters the battlefield, a player draws a card, a creature deals combat damage, etc.)
  2. Check if they actually trigger (e.g. "when a creature enters the battlefield" doesn't trigger for a land)
  3. Ask the players in which order they want to stack the triggers
  4. Put trigger ability objects on the stack
  5. And the rest is the common procedure of giving priority to players, resolving stack contents, checking state-based actions, etc.
\$\endgroup\$

You must log in to answer this question.

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