- Home /
How to go about storing each trading card's effects/powers in tables for AI to use?
Working on a trading card game I came up with. Ultimate goal is to write an AI that a human player can play against.
Seems like the best idea to store the cards and player made/AI generated decks is to use a local database like SQLite. I'm assuming two tables is enough - one for cards, one for decks. There are different types of cards such as monsters, abilities, missions, and few others.
Question is what would be the appropriate way to store each card's effects/powers so that AI(when it will be implemented) can understand the effects of the cards.
For example, a monster card has the following text on it:
"When this card enters into play your monsters gain +1 damage"
or an ability one
"Pay 3 mana, exhaust this ability(exhaust icon), draw one card from the top of your deck".
How to store this textual data in the table so that the AI can understand what the card does and make decisions based on it.
I haven't made the AI yet and not really sure how to, but I do need to get the database filled up with cards so that I can start implementing my Deck Manager.
Is there a better way to do this rather than using SQLite? It's going to be a single player game.
Answer by Jamora · Aug 23, 2013 at 03:28 PM
The thing with database tables is that you can't really ship them easily with your game. You'll either have to play the game on the computer that has the database or set up internet access to the database with an HTTP server and what-have-you. You might also be albe to include the database software with the game, install that with the installer for your game, ship the whole database with the game and do all access normally.
I think a better solution is to apply the OOP paradigm and create an abstract class for a Card, put all common card-functionality there, such as being drawn from a deck, discarding them and whatever else you can think of. Then create a new class for each specific card and have that extend the abstract Card.
public abstract class Card : MonoBehaviour{
public void Discard()
{/*implementation*/}
public string GetName(){ return this.GetType().ToString(); }
//this will be implemented by all the specific cards.
public abstract void ApplyEffect();
}
public class ManaStealerCard : Card{
public override void ApplyEffect ()
{/*implementation*/}
}
public class GainDamageCard : Card{
public override void ApplyEffect ()
{/*different implementation from ManaStealer*/}
}
You can then access all cards as the Card class, and whenever you need to apply their effects, just call the method and through the magic of polymorphism, the correct implementation will be executed. Like this:
Card manaCard = new ManaStealerCard();
Card damageCard = new GainDamageCard();
manaCard.ApplyEffect();
damageCard.ApplyEffect();
You will also need a way to create the cards. I would create a Card Factory that creates either only the script, or instantiates a prefab for a card, then adds the specific card script to it.
public enum Cards{
ManaStealer,
GainDamage
}
public static class CardDeck{
public static GameObject DrawRandom(){
Cards cardToCreate = (Cards)Random.Range(0,System.Enum.GetNames(typeof(Cards)).Length);
return CreateCard(cardToCreate);
}
public static GameObject Draw(Cards card){
return CreateCard(card);
}
private static GameObject CreateCard(Cards card){
return new GameObject(card.ToString());
}
}
This way you can get random cards from your deck, and apply their effects without explicitly knowing which card has been drawn. So instead of the previous way with the new
keyword, you would instead
CardDeck.DrawRandom().GetComponent<Card>().ApplyEffect();
or alternatively store it in an array representing a Player's current hand. It can then be used at your leisure.
EDIT:
I didn't read closely enough so missed you saying local database...
Yes, if you have 300 different behaviors, you need to implement them all somehow. I prefer to have all different behavior in different files, though it is possible to have one big file with multiple class declarations too. If you have 100 different behaviors, with 3 variants each, you can initialize the card randomly when it's created in the factory using an abstract method, say, public abstract void Initialize()
in Card
.
You can create constraints in how cards are created by creating a private static variable in your class. If for example, you only want one card with +3 damage, and the rest are 50/50 between 1 and 2 damage, your initialization code inside GainDamageCard
could look something like this:
private static bool plus3Created = false;
private int damage;
public override void Initialize(){
//has a 25% chance of spawning a +3 card if one hasn't been spawned before.
if(!plus3Created && Random.value > 0.75f){
damage = 3;
plus3Created = true;
}else
//the int version is exclusive; returns 1 or 2
damage = Random.Range(1,3);
}
@Jamora Interesting. Thing is though - I'm not going to ship it. Also, I said local database like SQLite which doesn't follow the client-server paradigm. It's just a file like CSV or X$$anonymous$$L but a full blown table just like for relational databases but you don't need the server since it's stored on the client. So I'll have to create classes for every different card I make? Say I have 300 cards. That's about 300 classes for every card's unique effect, unless some have similar effects that are only different in numbers such as: "+2 damage" ins$$anonymous$$d of "+1 damage" as stated in the above example? I.e. GainDamageCard(damageNumber) : Card {//implementation}
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
SQLite and Lists in C# 1 Answer
Best practices for multiple databases 1 Answer
Unity 4 Android Game cannot access SQLite DB (C# Script) 1 Answer