1. Hey! Guest! The 36th GMC Jam will take place between February 27th, 12:00 UTC - March 2nd, 12:00 UTC. Why not join in! Click here to find out more!
    Dismiss Notice

If I want cards in my game what's most correct / easy way? Such as MTG or Hearthstone type cards

Discussion in 'Programming' started by R3ZN4, Jan 24, 2020.

  1. R3ZN4

    R3ZN4 Member

    Joined:
    Dec 10, 2019
    Posts:
    12
    Just wondering about methods of getting my objects to be cards. (I by no means want the answer handed to me, but a general idea of what direction to head in would really be helfpful ) I have it in a sort of form right now using mainly math outputs to make the card game psuedo playable. I would like to expand this base form and try to add cards like we would normally see with different abilities. I thought perhaps making 1 card pool to pull from and then defining enemy decks based on a few random values... my main question would be how should I approach making the cards? Would it be multiple arrays kind of? So I set a group of sprites in an array and then based on which 1 is loaded those corresponding stats are then loaded and then "some code somewhere that I don't have done yet" is also loaded to perform actions such as taunt or block some damage next round etc etc.
     
  2. NightFrost

    NightFrost Member

    Joined:
    Jun 24, 2016
    Posts:
    2,090
    I would first define the cards as pure data. At least until GMS 2.3 update comes out with various new stuff (lightweight data objects etc), the most straightforward method to define data - at least I use this a lot - is enumerator indexed arrays. For basic example, let's assume all the data we have for the cards is name, cost, attack and defense. Let's also define just two cards, a Goblin and a Knight.

    First we define all our cards as enumerator values. An enumerator assigns an integer value for each of its member, starting from zero. Enumerators are global variables and can be referenced anywhere. (When game is compiled, enumerator references are replaced with actual numbers. You use them in code for convenience so you don't need to remember a bunch of numbers and have descriptive names instead.)
    Code:
    // Set these enumerators up in some descriptively named object, like obj_cards
    enum Card_Type {
       Goblin,
       Knight
    }
    This means Card.Goblin stands for value 0, and Card.Knight is 1. We define card data in same manner.
    Code:
    enum Card_Data {
       Name,
       Cost,
       Attack,
       Defense
    }
    
    With these, we can define arrays to hold the card data, and a convenience function that creates the cards, to save us some typing time.
    Code:
    // Card creation function:
    ///@function scr_card_create(type, name, cost, attack, defense)
    ///@description Creates a card data array.
    ///@param enum Card type enumerator.
    ///@param name Card name.
    ///@param cost Cost value.
    ///@param attack Attack value.
    ///@param defense Defense value.
    
    var _Card = [];
    _Card[Card_Data.Name] = argument[1];
    _Card[Card_Data.Cost] = argument[2];
    _Card[Card_Data.Attack] = argument[3];
    _Card[Card_Data.Defense] = argument[4];
    global.Cards[@ argument[0]] = _Card;
    
    Code:
    // Setting up the cards in obj_cards continues with this:
    global.Cards = [];
    scr_card_create(Card_Type.Goblin, "Goblin", 1, 1, 1);
    scr_card_create(Card_Type.Knight, "Knight", 3, 4, 4);
    
    Now you have a global.Cards array tha contains an array in each entry for a specific card. To for example figure out the attack value of the knight, you would:
    Code:
    var _This_Card = global.Cards[Card_Type.Knight];
    var _Attack_Value = _This_Card[Card_Data.Attack];
    
    Now you can just create a generic obj_card object and when you create instances out of it, you pass it the Card_Type enumerator value, which the instance can then use to fetch and display correct sprite, values and so on.
    Code:
    var _New_Card = instance_create_layer(_PosX, _PosY, "Card_Layer", obj_card);
    _New_Card.Type = Card_Type.Knight;
    
     
    Last edited: Jan 24, 2020
    jackquake and IndianaBones like this.
  3. robproctor83

    robproctor83 Member

    Joined:
    Sep 30, 2019
    Posts:
    290
    That's a good thought out system NightFrost, almost identical to how I have things in my own project. My biggest complaint though is that you have to manage the enums separate from the cards. I would prefer to define the enum in the card create function, but alas it's not possible with enums.

    And, maybe I am misunderstanding, but wouldn't you use _this_card instead of _card here?

    Code:
    var _This_Card = global.Cards[Card_Type.Knight];
    var _Attack_Value = _This_Card[Card_Data.Attack];
     
    NightFrost likes this.
  4. R3ZN4

    R3ZN4 Member

    Joined:
    Dec 10, 2019
    Posts:
    12
    Thanks a lot. I'll definitely be working on it!
     
  5. NightFrost

    NightFrost Member

    Joined:
    Jun 24, 2016
    Posts:
    2,090
    I picked the idea from this forum, as it had been discussed by one or more of the resident wizards. It has served me well enough as a database-lookalike. In addition to setters, I also tend to write getter scripts. Multiple layers of arrays in arrays can become a complex structure so I'll have the scripts do the spelunking for me, and I don't need to remember the exact array layout I had built. Accessor chaining coming in 2.3 will simplify writing that stuff too...
    Good catch, I fixed several typos right after posting but that one slipped me. I've fixed it in the earlier post now.
     
  6. R3ZN4

    R3ZN4 Member

    Joined:
    Dec 10, 2019
    Posts:
    12
    In the section "///@function scr_card_create(type, name, cost, attack, defense)" are you actually creating your own script within this code or is this a script that would be defined in another section? I am less than novice in coding to be sure so it's probably a dumb question sorry. ;)

    And then I don't quite understand the naming conventions where you are doing _Name_of_Stuff... does this allow you to then create an array Goblin_Name_of_Stuff??
     
  7. FrostyCat

    FrostyCat Member

    Joined:
    Jun 26, 2016
    Posts:
    4,851
    All that in the chunk you showed except for the first line is meant to go into a script named scr_card_create, and the ///@ comments are JSDoc comments.

    The "naming conventions" you talked about are enums, which in NightFrost's setup are named aliases for plain numbers used reference entries in an array. He doesn't want to be in a situation where he hard codes something like global.Cards[0], then later forgets that 0 stands for Goblin.

    Please, learn your basics and stop skipping steps. If you can't read the intent of NightFrost's script within 15 minutes, you're nowhere near the level needed to make a card game tick.
     
    Last edited: Jan 26, 2020
  8. R3ZN4

    R3ZN4 Member

    Joined:
    Dec 10, 2019
    Posts:
    12

    Umm gee thanks I guess?!? edit: it had quoted it twice
     
  9. R3ZN4

    R3ZN4 Member

    Joined:
    Dec 10, 2019
    Posts:
    12
    So when FrostyCat "answered" me he/she never actually answered this part of the question. I found it just now and wanted to post it for others to learn if they come across this. In the help manual in game maker type in the search JSDoc Script Comments. Basically if you use these correctly in making your scripts they will behave like the in game functions giving you cue's on what info is needed when you type in your script_name().
     

Share This Page