Author Topic: Programming a card game with easily edited card abilities  (Read 1968 times)

0 Members and 1 Guest are viewing this topic.

Offline Yip

  • Species: vulpes vulpes
  • *
  • Female
  • Posts: 4007
    • Furaffinity
Programming a card game with easily edited card abilities
« on: April 09, 2012, 03:52:11 pm »
I'm working on creating a digital version of a card game. However, there will need to be a lot of cards, and I'd prefer to avoid making the card abilities hard coded into the game. But I also want it in a way that new abilities can be easily added without needing to change the code. At first I was thinking I could store the card info in XML, but the problem is, I'm not sure how I could implement instructions from that. I was hoping to get some input from others that have some programming knowledge so I can decide which way to approach it before I get too deep in the code.

Offline redyoshi49q

  • Species: (*please see above*)
  • Avatar from Dexcat's MFF 2013 Photoshoot
  • *
  • Male
  • Posts: 2071
    • Enigma Cipher (software project)
Re: Programming a card game with easily edited card abilities
« Reply #1 on: April 09, 2012, 08:04:37 pm »
I only have a little experience in this style of coding.  I offer my suggestion with the expectation that it will more likely than not be trumped by a more experienced responder.  It's also a bit long; you have been warned.

I had a similar problem with Enigma Cipher.  I wanted to be able to easily add new forms of encryption that could be included with newly written levels.  I encapsulated a "layer" of encryption in a class called Layer.  This allowed the game's engine to be able to run the encryption for a given level without knowledge of how that encryption worked.  (In my case, it also allowed layers to reference other layers to create "hybrid" results; this may or may not be useful for your applications, depending on what "abilities" you intend to add to your cards.)  The end result was that there was only one section of my code that had to worry about what different types of layers existed, namely, the main function that actually initialized level objects.  Aside from this, the layers' functions were called when they might be needed to do something, and the layers took care of their own gritty details.

If I were in your position (I'm assuming C++, as that's the language I'm most proficient in), I would create an abstract class to encapsulate any card ability with generically defined virtual functions for any context under which a card ability might become relevant, with a passed in parameter that references a structure/class storing game state.  For example, this class would probably have a start of turn function, an end of turn function, a prepare to draw from deck function, a draw from deck function, and a draw this card from deck function, among other things, and the vast majority of these functions would do nothing (except perhaps ones like "discard this card" or "draw this card", which would then perform their corresponding default functions).  I would also imagine a const (or const-like) int to be declared uniquely in each child; that would allow you to give an order of execution for abilities on cards.  Cards themselves would be a class that contain, among other things, a vector/deque of pointers to instances of the ability class described earlier.

Abilities would inherit from this abstract class, and would only override the functions that they were relevant to.  For instance, if dredge from MtG was to be implemented in such a way, it would only override the "prepare to draw a card" function and, in a crude implementation, would offer the user the option to dredge that card if it was in the graveyard and, if they accepted, would discard X cards from the deck (X being a parameter to initialize the class stored in a child class variable) through calling the discard function of the top X cards of the deck in order (possibly triggering other card effects), add the dredged card to the hand, and set the game state to post-draw before returning.  Aside from this, the child class wouldn't have any other implementation (dredge doesn't do anything else).

The game engine would do little itself; it would store a game state struct/object, and repeatedly call the ability functions of each card present in a game loop (changing the game state to the next in most cases).  The actual function(s) of cards, if any, would be implemented in the calls to virtual functions in most cases.  Some game mechanics, such as a battle phase, that affect the entire field may be best done outside of the scope of any individual card (either built into the game engine or its own engine); you may even want to add an ability pointer vector to whatever entity you have serve this purpose, and add things like battle phase functionality as unique "abilities" that the battlefield itself has.

The code that generates your cards (whether through XML like you suggest or through hardcoding like I use in Enigma Cipher) would somehow need to be aware of what different ability child classes exist in order to initiate children of those classes.  If you implement an XML parser, you *might* be able to get around this by making a function pointer vector/deque in the header file of your ability parent class, have sections of global scope code in your ability children class's header files that, in each section of code, adds to this vector/deque a pointer to a static member function of the corresponding class, and making your XML generating code call each function of this vector/deque to determine whether the XML should generate a new ability and, if so, return a pointer to this dynamically allocated ability.  I'm not even sure if code like that would compile/work, but if it did, your XML parsing code would be able to automatically call helper functions for each child class simply by including each child class in its header file, and this list of includes would literally be the *only* section of code that would need to know about the various types of card abilities that exist.

I hope this made sense, and was helpful.  I might not have been clear in my explanation.
"Perfect normality is impossible.  Be unique!"
-- redyoshi49q




^ (click) Puzzle game!

Offline Hoagiebot

  • Sr. Member
  • Species: Thinking Machines Corporation CM-5/1056
  • Analyzing MLP w/ 135-GFLOPS of raw computing power
  • ****
  • Male
  • Posts: 437
    • Project Destiny Studios
Re: Programming a card game with easily edited card abilities
« Reply #2 on: April 09, 2012, 10:30:28 pm »
For storing your cards' attributes, XML is definitely one way that you could go, but I would suggest that a much better way might be to use an embedded database, since it would provide a much more robust and reliable form of data management.  There are many embedded database options that are available for programmers to choose from to integrate into their applications as well, such as Microsoft SQL Server Compact Edition (which is free to use and distribute) if you are using .Net, and these open source alternatives if you are using some other programming platform.  With an embedded database you can still take advantage of using objects in an object-oriented programming language such as C++ or C# like redyoshi49q mentioned, but at the same time you can also take advantage of all of the power that SQL-based relational databases provide for your data storage.  For example, adding and removing new cards and card-attributes would be as simple as adding and deleting database records, you could easily perform a SQL-based query to find all of the cards with a particular attribute, etc.  You could even store all of the cards' art in the database tables as BLOBs if you wanted.  Considering the fact that a card game such as the one that you are describing is almost entirely data-driven, you should definitely look into this.
« Last Edit: April 10, 2012, 05:45:26 am by Hoagiebot »

Offline Yip

  • Species: vulpes vulpes
  • *
  • Female
  • Posts: 4007
    • Furaffinity
Re: Programming a card game with easily edited card abilities
« Reply #3 on: April 11, 2012, 05:02:41 pm »
An embedded database sounds like a good idea, and I really like the idea of it having the art tied to the card's entry. However, I'm still not sure how to go about having elements in the database contain instructional code. That's the part I'm having trouble seeing. I could see how I could make an abstract class like what redYoshi appears to be taking about, but I'm not seeing how the database entry (or XML item or whataver) will tie in with it. Maybe if I made some kind of parser to read in instructions from a text field....  hmm... this project might be a lot more work that I originally was thinking it'd be.

Offline redyoshi49q

  • Species: (*please see above*)
  • Avatar from Dexcat's MFF 2013 Photoshoot
  • *
  • Male
  • Posts: 2071
    • Enigma Cipher (software project)
Re: Programming a card game with easily edited card abilities
« Reply #4 on: April 11, 2012, 05:46:19 pm »
An embedded database sounds like a good idea, and I really like the idea of it having the art tied to the card's entry. However, I'm still not sure how to go about having elements in the database contain instructional code. That's the part I'm having trouble seeing. I could see how I could make an abstract class like what redYoshi appears to be taking about, but I'm not seeing how the database entry (or XML item or whataver) will tie in with it. Maybe if I made some kind of parser to read in instructions from a text field....  hmm... this project might be a lot more work that I originally was thinking it'd be.

It seems you're wanting to incorporate behavioral functionality into a database system, and I don't know of any way to do that (moreover, I don't even know if it's realistically possible or practical).  The suggestion I provided allows you to implement a new function by writing a new source file for it.  The game's engine would be able to incorporate the functionality of the new file by reading new XML/database format versions that file makes possible without specific modifications to the game's engine.  You *would* need to add an include statement to your XML/database parsing code to incorporate whatever file you write, and you would either need to manually add a function call to a static function of your new class file in your parsing code or use shenanigans like I referred to in the last big paragraph of my first post.  (*edit: upon further research, it appears that the shenanigans I discussed in the last large paragraph of my previous post are not valid C/C++; part of me wishes that wasn't the case, given how powerful that particular solution would have been...*)

To better illustrate, I've included sample pseudocode for the closest solution that I can think of to what you want.

(*edit: post is still in progress; apparently, tab followed by enter *submits* a post instead of... well... yeah...*) Post is now done.

Spoiler: parser.h • show

#ifndef PARSER_H
#define PARSER_H

#include <vector>
#include "card.h" /* I'm assuming that cards are defined elsewhere */
#include "database.h"
/* I'm also assuming your DB parsing code is elsewhere;
 *   I have *no* experience in that department...
 */

#include "dredge.h"
/* you'd have to add an include for every new ability child class you make here*/

vector<Card> parse_DB(DB& database);

#endif PARSER_H


Spoiler: parser.c • show

#include "parser.h"

vector<Card> parse_DB(DB& database) {

vector<Card> parsedCards;
Card *newCard;
DB_entry entry;

while (database.hasEntries() ) {

newCard = new Card();
entry = database.nextEntry();

Dredge.parseAbility(newCard, entry);
/*you'd have to add a line here for every new ability you add as well*/

parsedCards.push_back(*newCard);
delete newCard;
}

return parsedCards;
}


Spoiler: dredge.h • show

#ifndef DREDGE_H
#define DREDGE_H

#include "ability.h"

#include <vector>
#include "card.h" /* I'm assuming that cards are defined elsewhere */
#include "database.h"
/* I'm also assuming your DB parsing code is elsewhere;
 *   I have *no* experience in that department...
 */

class Dredge : public Ability {

/* the functions in Ability you intend to override */

static void parseAbility(Card *newCard, DB_entry entry);

};

#endif // DREDGE_H


Spoiler: dredge.c • show

#include "spoiler.h"

/* implementation of *only* the ability class functions
 *   that the ability affects (as well as the static function)
 */




Spoiler: ability.h • show

#ifndef ABILITY_H
#define ABILITY_H

class Ability {

/* a bunch of virtual functions */

};

#endif // ABILITY_H


Spoiler: ability.c • show

#include "ability.h"

/* define the functions in the Ability class */

« Last Edit: April 11, 2012, 07:08:02 pm by redyoshi49q »
"Perfect normality is impossible.  Be unique!"
-- redyoshi49q




^ (click) Puzzle game!

Offline Avan

  • Species: Azemdyn Sabertooth Hyena
  • Gender: Non-Binary, YEEN.
  • *
  • Posts: 5010
    • Our FA
Re: Programming a card game with easily edited card abilities
« Reply #5 on: April 12, 2012, 03:51:51 am »
depending on how fancy you want to go, you could have it be scripted.
We are Dissociated Identities.

Avatar is of Avan-Syr (Saberyeen)
Old links to art sites we need to update:
Weasyl Page: https://www.weasyl.com/~avankaira
My FA page: http://www.furaffinity.net/user/avanwolf/

Steam: http://steamcommunity.com/id/avan_wolf/

Offline Yip

  • Species: vulpes vulpes
  • *
  • Female
  • Posts: 4007
    • Furaffinity
Re: Programming a card game with easily edited card abilities
« Reply #6 on: April 13, 2012, 04:45:43 pm »
depending on how fancy you want to go, you could have it be scripted.
What do you mean?