Skip to content

Instantly share code, notes, and snippets.

@LuizMoratelli
Last active June 2, 2024 14:12
Show Gist options
  • Save LuizMoratelli/2741e001401f2424a61cc92f59684bd8 to your computer and use it in GitHub Desktop.
Save LuizMoratelli/2741e001401f2424a61cc92f59684bd8 to your computer and use it in GitHub Desktop.
[TCG Engine] 🤝 [mopsicus/uis]

0. Explanation

Mopsicus/UIs will be used to avoid a lot of instanciate of cards, that could cause some lags when you have a TON of cards. With this implementation, the Scroller will only spawn some rows, like ~7 and replace the values when the user scroll down and up.

1. Install mopsicus/uis (https://github.com/mopsicus/uis)

2. Edit CardData.cs

public static CardData GetCard(int index)
{
    if (index >= card_list.Count)
        return null;

    return card_list[index];
}

public static int GetCardCount()
{
    return card_list.Count;
}

3. Edit CollectionPanel.cs

//...
using UIS;

public class CollectionPanel : UIPanel
{
  private List<CardDataQ> collection_cards = new List<CardDataQ>();
  private int cards_per_row = 3;

  [SerializeField]
  Scroller list = null;
  
  protected override void Start()
  {
    base.Start();

    list.OnFill += OnFillItem;
    list.OnHeight += OnHeightItem;
    //...
  }
  
  protected override void Awake()
  {
    base.Awake();
    //...
    cards_per_row = list.Prefab.transform.childCount;
  }
  
  void OnFillItem(int index, GameObject item)
  {
    for (int i = 0; i < cards_per_row; i++)
    {
      CollectionCard dCard = item.transform.GetChild(i).GetComponent<CollectionCard>();
      int position = index * cards_per_row + i;

      if (item.activeSelf != index * cards_per_row < collection_cards.Count)
          item.SetActive(!item.activeSelf);

      if (position >= collection_cards.Count)
      {
       if (dCard.gameObject.activeSelf)
           dCard.gameObject.SetActive(false);
      }
      else
      {
       CardDataQ card = collection_cards[position];
       dCard.SetCard(card.card, card.variant, 0);
       dCard.onClick += OnClickCard;
       dCard.onClickRight += OnClickCardRight;
       
       if (!dCard.gameObject.activeSelf)
           dCard.gameObject.SetActive(true);

       UserData udata = Authenticator.Get().UserData;
       bool owned = IsCardOwned(udata, card.card, card.variant, 1);
       int quantity = udata.GetCardQuantity(card.card, card.variant);
       dCard.SetQuantity(quantity);
       dCard.SetGrayscale(!owned);
      }
    }
  }

  int OnHeightItem(int index)
  {
      return 360;
  }

  protected override void Update()
  {
      base.Update();
  }
  
  public void RefreshCards()
  {
    collection_cards.Clear();

    UserData udata = Authenticator.Get().UserData;
    if (udata == null)
        return;

    VariantData variant = VariantData.GetDefault();
    VariantData special = VariantData.GetSpecial();
    if (toggle_foil.isOn && special != null)
        variant = special;

    List<CardDataQ> all_cards = new List<CardDataQ>();

    foreach (CardData icard in CardData.GetAll())
    {
      CardDataQ card = new CardDataQ();
      card.card = icard;
      card.variant = variant;
      card.quantity = udata.GetCardQuantity(icard, variant);
      all_cards.Add(card);
    }

    if (filter_dropdown == 0) //Name
      all_cards.Sort((CardDataQ a, CardDataQ b) => { return a.card.title.CompareTo(b.card.title); });
    if (filter_dropdown == 1) //Attack
      all_cards.Sort((CardDataQ a, CardDataQ b) => { return b.card.attack == a.card.attack ? b.card.hp.CompareTo(a.card.hp) : b.card.attack.CompareTo(a.card.attack); });
    if (filter_dropdown == 2) //hp
      all_cards.Sort((CardDataQ a, CardDataQ b) => { return b.card.hp == a.card.hp ? b.card.attack.CompareTo(a.card.attack) : b.card.hp.CompareTo(a.card.hp); });
    if (filter_dropdown == 3) //Cost
      all_cards.Sort((CardDataQ a, CardDataQ b) => { return b.card.mana == a.card.mana ? a.card.title.CompareTo(b.card.title) : a.card.mana.CompareTo(b.card.mana); });

    foreach (CardDataQ card in all_cards)
    {
      CardData icard = card.card;
      
      if (!icard.deckbuilding) continue;
      
      if (filter_team == null || filter_team == icard.team)
      {
        bool owned = card.quantity > 0;
        RarityData rarity = icard.rarity;
        CardType type = icard.type;

        bool owned_check = (owned && toggle_owned.isOn)
          || (!owned && toggle_not_owned.isOn)
          || toggle_owned.isOn == toggle_not_owned.isOn;

        bool type_check = (type == CardType.Character && toggle_character.isOn)
          || (type == CardType.Spell && toggle_spell.isOn)
          || (type == CardType.Artifact && toggle_artifact.isOn)
          || (type == CardType.Equipment && toggle_equipment.isOn)
          || (type == CardType.Secret && toggle_secret.isOn)
          || (type == CardType.Hero && toggle_hero.isOn)
          || (!toggle_character.isOn && !toggle_spell.isOn && !toggle_artifact.isOn && !toggle_equipment.isOn && !toggle_secret.isOn && !toggle_hero.isOn);

        bool rarity_check = (rarity.rank == 1 && toggle_common.isOn)
          || (rarity.rank == 2 && toggle_uncommon.isOn)
          || (rarity.rank == 3 && toggle_rare.isOn)
          || (rarity.rank == 4 && toggle_mythic.isOn)
          || (!toggle_common.isOn && !toggle_uncommon.isOn && !toggle_rare.isOn && !toggle_mythic.isOn);

        string search = filter_search.ToLower();
        bool search_check = string.IsNullOrWhiteSpace(search)
          || icard.id.Contains(search)
          || icard.title.ToLower().Contains(search)
          || icard.GetText().ToLower().Contains(search);

        if (owned_check && type_check && rarity_check && search_check)
        {
          collection_cards.Add(card);
        }
      }
    }

    list.RecycleAll();
    if (collection_cards.Count != 0)
    {
     var row_amount = collection_cards.Count / (float)cards_per_row;
     list.RefreshViews(Mathf.CeilToInt(row_amount));
     list.InitData(Mathf.CeilToInt(row_amount));
    }

    scroll_rect.verticalNormalizedPosition = 1f;
  }
  
  // You can remove all references to RefreshCardsQuantities because now they update OnFill
}

4. Setup de Scene (Main)

4.1 Remove the Grid Component (path UICanvas/CollectionPanel/Scroll View/Viewport/Content/Grid)

4.2 Add Scroller to ScrollView (to setup it fully you will need the prefab done at 4.4)

image

4.3 Link Scroller to CollectionPanel

image

4.4 Create a CardDeckRow Prefab (I set 3 cards each row)

image

4.5 Remove CardDeckRow from scene, it will be added in runtime

4.6 Have Fun :D

5. Result

5.1 List

image

5.2 Filter Owned

image

5.3 Filter Foil

image

5.4 Filter <= 3

image

5.5 Filter no results

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment