6
\$\begingroup\$

I'm trying to create cards for a ccg/tcg that are completely "data-driven" from an xml/json/external file. I've read multiple articles on this issue already, even here on stack exchange, but i can't figure out how to actually code this. I have a simple example:

My two cards have the following abilities

1) "Increase the value of all adjacent red cards by 1"

2) "Increase the value of this card by the amount of all adjacent red cards"

In my code i have the following functions (pseudo) that i need to accomplish these effects:

Increase(targetCards, byValue) // increases a card's value by another value
FindCards(filter=adjacent) // returns all adjacent cards
FilterCardsBy(filter=isRed) // returns only red cards
Count(targetCards) // counts the number of cards

To create effect 1 i would use the functions like this:

Increase(FilterCards(FindCards(adjacent), isRed), 1);

and to create effect 2 i would use:

Increase(this, Count(FilterCards(FindCards(adjacent), isRed)));

So here's the problem: I have no clue how i can describe these functions in my external file and also i have no clue how i actually tell my functions to work in this combination to achieve the desired effects. Maybe i'm misunderstanding the concept here but as far as i understood and described here i can create some pseudo script/code in my external file that then my code can interpret and execute on. But i feel i somehow missing the middle part where i write code to interpret these commands i'm defining in the external file.

Anyone with experience here that can give me some super simple starter ideas on how to takle this. Especially the part where i can combine several functions into one.

\$\endgroup\$
  • \$\begingroup\$ In addition to my answer this pattern is kind of related, in the sense it separates design from code. \$\endgroup\$ – lozzajp Sep 28 '16 at 10:22
3
\$\begingroup\$

When you have complex logic in the mechanics of individual cards, then it might be best to express that logic with a scripting language. But if you really want to go for a completely domain-driven approach, you might go for something in between: Markup which describes logic.

Both of the effects mentioned in the question could be called an "adjacency effect". It's an effect which triggers if an adjacent card fulfills a certain condition. The difference is that one is a bonus on the adjacent card, the other one on the card itself (which stacks for each card which fulfills the condition). In JSON, these two effects could be expressed as a triplet of adjacencyCondition, self-effect and adjacent-effect.

{    
    "adjacencyCondition: { color: "red" },
    "self": { "value": 1 },
    // "adjacent": undefined
}

{    
    "adjacencyCondition": { "color": "red" },
    // self: undefined
    "adjacent": { "value": 1 },
},

If you don't like JSON, feel free to use XML, YAML, INI or whatever markup language you prefer instead. But I would not recommend you to invent your own. When you use an existing markup language, you will likely find a well-tested library for parsing it. When you develop your own, you will have to spend countless hours writing your own parser. This will be far harder than it sounds at first. And subtle bugs in your parser can and will cause you frustration to no end.

Your program code to apply these would look like this (pseudocode):

if (card has 'adjacencyCondition') {
    foreach (adjacent card) {
        if (adjacent card has all attributes specified by 'adjacencyCondition') {
              increase adjacent card attributes by everything specified in 'adjacent'
              increase current card attributes by everything specified in 'self'
        }
    }
}

This system can easily be enhanced to have more conditions than just adjacencyCondition (where "adjacent" doesn't necessarily makes sense, but other fields might). Your should allow cards to have an array of effects to allow cards which have more than one effect. In that case you might also have an unconditional condition which allows you to define inherent attributes of cards. But I have no idea how your game mechanics look like or what the theme of your game is, so I could only guess what could be useful for you.

Anyway, here is an example of a red card with a value of 3 which counts as both a kitten and a zombie, which turns all adjacent space stations green and gets +1 for every blue card controlled by the opponent:

{   "name": "Bob the Zombie Kitten",
    "effects": [
         {
             "unconditional": true,
             "self": {
                 "color": "red",
                 "traits": [ "zombie", "kitten" ],
                 "value": 3,
             }
          },
          { 
            "adjacentCondition": { "traits": "space_station" },
            "adjacent" : { "color": "green" }
          },

          { 
            "allCondition": { "owner": "opponent", "color": "blue" },
            "self" : { "value": 1 }
          },
    ]
}
\$\endgroup\$
1
\$\begingroup\$

I will expand on this in a bit when I have more time but essentially, as you say, are going for a data driven design approach for your game.

This means you are defining your cards in XML or JSON format etc. What you should really do is pick one and stick with it (not necessarily forever, but for your first technical demos and understanding). Alternatively you can just create your own format and then write the code to interpret it. Imagine this inside a .txt file.

Card=
Name: Test
Value: 5
Color: Red
Endcard

Just a simple example, but now you have a defined piece of data that is more human readable and your designers can edit a text file instead of letting them have access to code.

So now you have a definition of the card and can separate data from code.

Your next step will be to write some form of interpreter (later you can change this to serializing/deserializing), a psuedo code of it may look like:

Card card = new Card();

var file = File.LoadFile("data.txt");
string line;
while (line != "Endcard")
{
line = file.ReadLine();
if (line == "Card=")
  {
    card.name = file.ReadLine().StripString("Name: "); 
    /* this will read in name and strip the Name: part so the variable card.name 
       now contains the string "Test". Please not you will have to implement
       the stripping part or use some in built language feature */
    card.value = file.ReadLine().StripString("Value: ");
    card.color = file.ReadLine().StripString("Color: ");
  }

}

So now your program has read in the data text file and converted it into a Card object.

I hope that helps you see it a bit clearer, sorry for poor formatting and again I will fix this up and write a fuller answer later with more time.

p.s. keep in mind the psuedoness nature of the code so far, the file reading employed is very error prone but I am just trying to communicate the idea across to you.

\$\endgroup\$
  • \$\begingroup\$ Hi, thanks for your answer. To make this a bit clearer: I'm not asking about defining static properties of cards by external data, but having a system where i can build the effects each card can do. I believe this is something else than just saying this cards has a static value of X. This is about saying this card can perform multiple actions that somehow need to be interpreted by my code and then be executed. \$\endgroup\$ – Arnold from Tinytouchtales Sep 28 '16 at 10:54
  • \$\begingroup\$ This pattern then may help out a bit as well or at least spark some more thought for you :) \$\endgroup\$ – lozzajp Sep 28 '16 at 10:59
  • \$\begingroup\$ I don't fully understand your problem but a simple solution may be higher level functions. So you have three effect functions. EffectOne(); EffectTwo(); EffectThree(); Then you have some functions that call them in specific orders to get the overall effect you want: FunctionOne() { EffectOne(); EffectThree(); } FunctionTwo { EffectThree(); EffectOne(); } \$\endgroup\$ – lozzajp Sep 28 '16 at 11:05
  • 1
    \$\begingroup\$ That entire book Game Programming Patterns by Robert Nystrom is recommended by many including myself, the entire thing is well worth a read. \$\endgroup\$ – lozzajp Sep 28 '16 at 11:14
  • 1
    \$\begingroup\$ Thanks for the help. I actually know the website, but didn't know where to look. \$\endgroup\$ – Arnold from Tinytouchtales Sep 28 '16 at 11:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.