I need help to define an architecture for my card game

Hello all,
I am currently working on a game inspired by Ratropolis, which means that the player will have to play cards from his hand to achieve certain actions in the world, like get some money or this kind of things.

I am not sure how to implement this, and I am very confused to say the least. Basically, so far I had been using a Scriptable Object called CardData, which looks like this : (please note that the CardsEffect line was not present until yesterday, and this is what I am confused about)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;

[CreateAssetMenu]
public class CardData : ScriptableObject
{
    //This will contain all the cards information.
    public string cardName, description;
    public int moneyCost, natureCost, foodCost;
    public Texture2D texture; //this is for prototyping only, textures will be replaced by a prefab.
    public CardsEffect cardEffect; // CardsEffect is a public class that I created for my spells class to Inherit from. I am not sure about this tho
}

Searching online, I saw that many people recommanded to create a public class that would hold the voids of the effects, so I could create a class for each card inheriting from it. So this is what I did :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[System.Serializable]
public class CardsEffect
{
    private GameObject resourceController;
    public CardsEffect()
    {

    }

    public bool unplayable;

    [Header("When played")]
    public int moneyBonus;
    public int natureBonus;
    public int foodBonus;

    [Header("When drawn")]
    public int drawMoneyBonus;
    public int drawNatureBonus;
    public int drawFoodBonus;
   
    public void OnDraw()
    {

    }

    public void OnPlay()
    {

    }
}

But I realize I don’t really know how to use this. Basically, what I was thinking about was creating public voids in the CardsEffect class with parameters, like this so I could easily call the voids from the inheriting classes, but I’m not sure it’s good.

DrawCards(int cardsToDraw)
{
  target player draws cardsToDraw cards;
}

Also, I don’t understand how to implement these classes since they don’t inherit from MonoBehaviour, I can’t attach them to my ScriptableObject, and I can’t make a CardsEffect using the voids. So as you can see, I am very confused, and I would really appreciate some advices about this.

Thanks for reading me,
Best regards

Identify where you want to divide your game between the actual logical state of the cards, what they are, what they do, etc., and the presentation to the player, mostly using UnityEngine stuff.

In other words, for a traditional card game, the cards themselves might only have suit and rank as far as the game logic is concerned, and perhaps a boolean value indicating if they are flipped face up or face down. But each card also has a presentation, probably a graphic or prefab that they look like.

But in poker if you combine 5 cards to make a hand, now you need the abstract concept of evaluating that hand, and that has NOTHING to do with Unity, but you would use Unity to present the results.

If you drew A, A, K, 9, 5 in poker, that would evaluate as “Pair of Aces” and the code to detect that would then signal to the user that you have a pair, perhaps by showing the word “PAIR” or “PAIR ACES” or just showing a graphic. NONE of the latter affects the calculation deciding that you have a pair or not. That’s what dividing the game between logic and presentation gets you.

Card games can be tricky because what you have to encode is the rules of any given game that you’re contemplating. Something like a complex Magic: The Gathering or Hearthstone game is crazy in terms of all the different ways cards interact with each other and with the state of the game itself, or even sub-combinations of other cards.

If you want to start out and get a feel for what is involved in a stats card-combat kinda game, probably the dead-simplest one would be the game of war:

https://bicyclecards.com/how-to-play/war/

If that one is too simple, expand it into something like Top Trumps, where each card has multiple axes of value:

https://en.wikipedia.org/wiki/Top_Trumps

Hello, and thank you for your answer !

So basically what I ended up doing is having a class called CardData (might change that since I don’t find it very clear) that holds cards logic :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CardData
{
    public bool unplayable = false;

    public string name;
    public string description;

    public int natureCost;
    public int foodCost;
    public int moneyCost;
    public int actionCost;
   
    public virtual void OnDraw()
    {

    }

    public virtual void OnPlay()
    {

    }

    public void GainMoney(int moneyBonus)
    {
        GameObject.FindGameObjectWithTag("ResourceController").GetComponent<MoneyController>().money += moneyBonus;
    }

    public void GainFood(int foodBonus)
    {
        GameObject.FindGameObjectWithTag("ResourceController").GetComponent<FoodController>().foodPoints += foodBonus;
    }

    public void GainNature(int natureBonus)
    {
        GameObject.FindGameObjectWithTag("ResourceController").GetComponent<NatureController>().naturePoints += natureBonus;
    }
}

Then I create cards that inherit from it and override its methods. This is a card example called “Packing Up” :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PackingUp : CardData
{
    public PackingUp()
    {
        name = "Packing Up";
        description = "+2 golds";
    }
    public override void OnPlay()
    {
        base.OnPlay();
        GainMoney(2);
    }
}

I also have a Dictionnary that is a MonoBehaviour attached to a GameManager GameObject that holds all the cards, and a List attached to a DeckManager to which I can add the CardDatas of the Dictionnary.

It’s working like a charm ! What do you think about this system ?