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)
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;
}
//...
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
}
If your heights are well setup you could consider using this below to avoid the magic numbers in the original version;