I’m getting my data for the cards as a JSON, it’s added to my deck list but when I start drawing the card’s ID which dictates the card’s info isn’t the same but random.
For example:
{ "cardsWithThisId": [ 0, 0, 10, 0, 10, 0, 10, 0, 10] }
is in my JSON this should mean I have:
- 10 cards with the ID of 2
- 10 cards with the ID of 4
- 10 cards with the ID of 6
- 10 cards with the ID of 8
Since it’s 0 - 8 currently due to the elements but now it’s just ID = 8
PlayerDeck.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using System.IO;
public class PlayerDeck : MonoBehaviour
{
public List<Card> deck = new List<Card>();
public List<Card> container = new List<Card>();
public static List<Card> staticDeck = new List<Card>();
private CustomDeckData deckData;
public int x;
public static int deckSize;
public GameObject cardInDeck1;
public GameObject cardInDeck2;
public GameObject cardInDeck3;
public GameObject cardInDeck4;
public GameObject CardBack;
public GameObject CardToHand;
public GameObject Deck;
public GameObject[] Clones;
public GameObject Hand;
// Reference to ThisCard script
public ThisCard thisCardScript;
public TextMeshProUGUI LoseText;
public GameObject LoseTextGameObject;
// Start is called before the first frame update
void Start()
{
LoadDeckFromJSON(); // Load the deck from JSON
thisCardScript = GetComponentInChildren<ThisCard>();
StartCoroutine(StartGame());
}
// Update is called once per frame
void Update()
{
if (deckSize <= 0)
{
LoseTextGameObject.SetActive(true);
LoseText.text = "Deck Out, You Lose";
}
staticDeck = deck;
if (deckSize < 30)
{
cardInDeck1.SetActive(false);
}
if (deckSize < 20)
{
cardInDeck2.SetActive(false);
}
if (deckSize < 2)
{
cardInDeck3.SetActive(false);
}
if (deckSize < 1)
{
cardInDeck4.SetActive(false);
}
if (ThisCard.drawX > 0)
{
StartCoroutine(Draw(ThisCard.drawX));
ThisCard.drawX = 0;
}
if (TurnSystem.startTurn == true)
{
StartCoroutine(Draw(1));
TurnSystem.startTurn = false;
}
}
void LoadDeckFromJSON()
{
// Load the JSON file into a string
string jsonString = File.ReadAllText(Application.persistentDataPath + "/deck.json");
// Parse the JSON string into a CustomDeckData object
deckData = JsonUtility.FromJson<CustomDeckData>(jsonString);
if (deckData != null)
{
// Clear the existing deck
deck.Clear();
// Populate the deck based on the loaded data
for (int i = 0; i < deckData.cardsWithThisId.Length; i++)
{
int cardId = deckData.cardsWithThisId[i];
// Find the corresponding card in the database and add it to the deck
for (int j = 0; j < cardId; j++)
{
Card foundCard = CardDataBase.cardList.Find(card => card.id == i);
if (foundCard != null)
{
deck.Add(foundCard);
}
}
}
deckSize = deck.Count; // Set the deck size based on the loaded deck
}
}
IEnumerator Example()
{
yield return new WaitForSeconds(1);
Clones = GameObject.FindGameObjectsWithTag("Deck");
foreach (GameObject Deck in Clones)
{
Destroy(Deck);
}
}
IEnumerator StartGame()
{
// Draw 4 initial cards
for (int i = 0; i <= 4; i++)
{
DrawCardToHand();
yield return new WaitForSeconds(1);
}
}
public void DrawCardToHand()
{
if (deckData != null && deckData.cardsWithThisId.Length > 0)
{
// Iterate through the loaded deck IDs
foreach (int cardId in deckData.cardsWithThisId)
{
// Find the corresponding card in the database
Card drawnCard = CardDataBase.cardList.Find(card => card.id == cardId);
// If the card is found, draw it and remove from the deck
if (drawnCard != null)
{
// Set the ID on the ThisCard script before instantiating
if (thisCardScript != null)
{
thisCardScript.thisID = drawnCard.id;
}
else
{
Debug.LogError("thisCardScript is null");
}
// Instantiate the CardToHand object
Instantiate(CardToHand, transform.position, transform.rotation);
deckSize--;
return; // Exit the method after drawing one card
}
}
Debug.LogWarning("No more cards to draw from the loaded deck.");
}
else
{
Debug.LogWarning("Deck data is missing or empty, cannot draw more cards.");
}
}
public void Shuffle()
{
for (int i = 0; i < deckSize; i++)
{
container[0] = deck[i];
int randomIndex = Random.Range(i, deckSize);
deck[i] = deck[randomIndex];
deck[randomIndex] = container[0];
}
Instantiate(CardBack, transform.position, transform.rotation);
StartCoroutine(Example());
}
IEnumerator Draw(int x)
{
for (int i = 0; i < x; i++)
{
yield return new WaitForSeconds(1);
DrawCardToHand();
}
}
}
[System.Serializable]
public class CustomDeckData
{
public int[] cardsWithThisId;
}
This is the card code if you want to check it out though I wish to focus on the playerdeck code.
ThisCard.cs
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.UI;
public class ThisCard : MonoBehaviour
{
private List<Card> thisCardList = new List<Card>();
public List<Card> deck = new List<Card>();
public int thisID;
public int id;
public string cardName;
public int cost;
public int power;
public string cardDescription;
public TextMeshProUGUI nameText;
public TextMeshProUGUI costText;
public TextMeshProUGUI powerText;
public TextMeshProUGUI descriptionText;
public Sprite thisSprite;
public Image thatImage;
public Image frame;
public bool cardBack;
CardBack CardBackScript;
public GameObject Hand;
public int numberOfCardsInDeck;
public bool canBeSummon;
public bool summoned;
public GameObject battleZone;
public static int drawX;
public int drawXcards;
public int addXmaxGil;
public GameObject attackBorder;
public GameObject Target;
public GameObject Enemy;
public bool summoningSickness;
public bool cantAttack;
public bool canAttack;
public static bool staticTargeting;
public static bool staticTargetingEnemy;
public bool targeting;
public bool targetingEnemy;
public bool onlyThisCardAttack;
public GameObject summonBorder;
public bool canBeDestroyed;
public GameObject Graveyard;
public bool beInGraveyard;
public int hurted;
public int actualpower;
public int returnXcards;
public bool useReturn;
public int resurrectXcards;
public static bool UcanReturn;
public int healXpower;
public bool canHeal;
public static bool useRevive;
public int boostXpower;
public bool canBoost;
public GameObject EnemyZone;
public AICardToHand aiCardToHand;
public bool spell;
public int damageDealtBySpell;
public bool dealDamage;
public bool stopDealDamage;
public bool ward;
public bool directattack;
public GameObject wardguard;
// Start is called before the first frame update
void Start()
{
CardBackScript = GetComponent<CardBack>();
if (CardDataBase.cardList.Count > 0)
{
// Add the last card from cardList to deck
deck.Add(CardDataBase.cardList[CardDataBase.cardList.Count - 1]);
thatImage.sprite = deck[0].thisImage;
}
//UpdateUI();
canBeSummon = false;
summoned = false;
drawX = 0;
canAttack = false;
summoningSickness = true;
Enemy = GameObject.Find("Enemy HP");
targeting = false;
targetingEnemy = false;
beInGraveyard = false;
canHeal = true;
canBoost = true;
directattack = true;
EnemyZone = GameObject.Find("EnemyZone");
Graveyard = GameObject.Find("MyGraveyard");
}
// Update is called once per frame
void Update()
{
Hand = GameObject.Find("Hand");
if (this.transform.parent == Hand.transform)
{
cardBack = false;
}
if (deck.Count > 0)
{
id = deck[0].id;
cardName = deck[0].cardName;
cost = deck[0].cost;
power = deck[0].power;
actualpower = power - hurted;
cardDescription = deck[0].cardDescription;
thisSprite = deck[0].thisImage;
drawXcards = deck[0].drawXcards;
addXmaxGil = deck[0].addXmaxGil;
returnXcards = deck[0].returnXcards;
healXpower = deck[0].healXpower;
boostXpower = deck[0].boostXpower;
spell = deck[0].spell;
damageDealtBySpell = deck[0].damageDealtBySpell;
ward = deck[0].ward;
resurrectXcards = deck[0].resurrectXcards;
}
// Check for color condition using the color property of the Card class
if (deck[0].color == "White")
{
frame.color = new Color32(255, 255, 255, 255); // Set the color to white
}
else if (deck[0].color == "Blue")
{
frame.color = new Color32(26, 109, 236, 255); // Set the color to white
}
else if (deck[0].color == "Green")
{
frame.color = new Color32(122, 236, 26, 255); // Set the color to white
}
else if (deck[0].color == "Black")
{
frame.color = new Color32(51, 32, 32, 255); // Set the color to white
}
CardBackScript.UpdateCard(cardBack);
UpdateUI();
if (this.tag == "Clone")
{
deck[0] = PlayerDeck.staticDeck[PlayerDeck.deckSize - 1];
PlayerDeck.deckSize--;
cardBack = false;
this.tag = "Untagged";
}
if (this.tag != "Clone")
{
if (TurnSystem.currentGil >= cost && summoned == false && beInGraveyard == false && TurnSystem.isYourTurn ==true)
{
canBeSummon = true;
}
else
{
canBeSummon = false;
}
if (canBeSummon == true)
{
gameObject.GetComponent<Draggable>().enabled = true;
}
else
{
gameObject.GetComponent<Draggable>().enabled = false;
}
battleZone = GameObject.Find("Zone");
if (!summoned && this.transform.parent == battleZone.transform)
{
Summon();
}
if(ward == true && summoned == true)
{
wardguard.SetActive(true);
}
else
{
wardguard.SetActive(false);
}
}
if(canAttack == true && beInGraveyard == false )
{
Debug.Log("Can attack1.");
attackBorder.SetActive(true);
}
else
{
Debug.Log("Can't attack1.");
attackBorder.SetActive(false);
}
if(TurnSystem.isYourTurn == false && summoned == true)
{
summoningSickness = false;
cantAttack = false;
}
if(TurnSystem.isYourTurn == true && summoningSickness == false && cantAttack == false)
{
canAttack = true;
}
else
{
canAttack = false;
}
targeting = staticTargeting;
targetingEnemy = staticTargetingEnemy;
if(targetingEnemy == true)
{
Target = Enemy;
}
else
{
Target = null;
}
if(targeting == true && onlyThisCardAttack == true)
{
Attack();
}
if(canBeSummon == true || UcanReturn == true && beInGraveyard == true || useRevive == true && beInGraveyard == true)
{
summonBorder.SetActive(true);
}
else
{
summonBorder.SetActive(false);
}
/* if (canBeSummon == true || useRevive == true && beInGraveyard == true)
{
summonBorder.SetActive(true);
Debug.Log("revive border test.");
}
else
{
summonBorder.SetActive(false);
}*/
if (actualpower <= 0 && spell == false)
{
Destroy();
canBeDestroyed = true;
}
if(returnXcards > 0 && summoned == true && useReturn == false && TurnSystem.isYourTurn == true)
{
Return(returnXcards);
useReturn = true;
}
if (resurrectXcards > 0 && summoned == true && useRevive == false && TurnSystem.isYourTurn == true)
{
Revive(resurrectXcards);
useRevive = true;
}
if (TurnSystem.isYourTurn == false)
{
useRevive = false;
useReturn = false;
}
if(canHeal == true && summoned == true)
{
Heal();
canHeal = false;
}
if(canBoost == true && summoned == true)
{
// AttackBoost();
// canBoost = false;
}
if(damageDealtBySpell >0)
{
dealDamage = true;
}
if(dealDamage == true && this.transform.parent == battleZone.transform && spell ==true)
{
Debug.Log("spell test1.");
attackBorder.SetActive(true);
}
else if(dealDamage == false && this.transform.parent == battleZone.transform && spell == true)
{
Debug.Log("spell test2.");
attackBorder.SetActive(false);
}
if(dealDamage == true && this.transform.parent == battleZone.transform)
{
Debug.Log("Attempting to speelll test.");
dealxDamage(damageDealtBySpell);
}
if(stopDealDamage == true)
{
Debug.Log("Stop deal damage test.");
attackBorder.SetActive(false);
dealDamage = false;
}
if(this.transform.parent == battleZone.transform && spell == true && dealDamage == false)
{
Debug.Log("Spell gone");
canBeDestroyed = true;
Destroy();
}
foreach (Transform child in EnemyZone.transform)
{
AICardToHand childAICard = child.GetComponent<AICardToHand>();
if (childAICard.ward == true)
{
directattack = false;
}
else
{
directattack = true;
}
}
}
public void Summon()
{
TurnSystem.currentGil -= cost;
summoned = true;
MaxGil(addXmaxGil);
drawX = drawXcards;
}
public void MaxGil(int x)
{
TurnSystem.maxGil += x;
}
void UpdateUI()
{
nameText.text = cardName;
costText.text = cost.ToString();
powerText.text = actualpower.ToString();
descriptionText.text = cardDescription;
thatImage.sprite = thisSprite;
}
public void Attack()
{
if (canAttack && summoned && Target != null)
{
Debug.Log("Attempting to attack.");
if (Target == Enemy && directattack == true)
{
Debug.Log("Attacking Enemy");
EnemyHp.staticHp -= power;
targeting = false;
cantAttack = true;
}
}
else
{
// Debug.Log("Attempting to attack AI.");
foreach (Transform child in EnemyZone.transform)
{
AICardToHand childAICard = child.GetComponent<AICardToHand>();
if ( childAICard.isTarget == true && cantAttack == false)
{
Debug.Log("Target found in EnemyZone.");
childAICard.hurted += actualpower; // Adjusting hurted value by the power of the attacking card
hurted = childAICard.actualpower;
cantAttack = true;
}
/* else
{
Debug.LogError("AICardToHand component not found or conditions not met on the target AI card.");
}*/
}
}
}
public void UntargetEnemy()
{
staticTargetingEnemy = false;
}
public void TargetEnemy()
{
staticTargetingEnemy = true;
}
public void StartAttack()
{
staticTargeting = true;
}
public void StopAttack()
{
staticTargeting = false;
}
public void OneCardAttack()
{
onlyThisCardAttack = true;
}
public void OneCardAttackStop()
{
onlyThisCardAttack = false;
}
public void Destroy()
{
Graveyard = GameObject.Find("MyGraveyard");
if(canBeDestroyed == true)
{
this.transform.SetParent(Graveyard.transform);
canBeDestroyed = false;
summoned = false;
beInGraveyard = true;
hurted = 0;
}
}
public void Revive(int x)
{
for (int i = 0; i <= x; i++)
{
ReviveCard();
}
}
public void ReviveCard()
{
Debug.Log("Revive card test.");
useRevive = true;
actualpower += power;
}
public void Return(int x)
{
for(int i = 0; i <= x; i++)
{
ReturnCard();
}
}
public void ReturnCard()
{
UcanReturn = true;
}
public void ReturnThis()
{
if (beInGraveyard == true && UcanReturn == true && Graveyard.transform.childCount > 0)
{
this.transform.SetParent(Hand.transform);
UcanReturn = false;
beInGraveyard = false;
summoningSickness = true;
}
else if (beInGraveyard == true && useRevive == true && Graveyard.transform.childCount > 0 && spell == false)
{
this.transform.SetParent(battleZone.transform);
useRevive = false;
beInGraveyard = false;
summoningSickness = true;
}
/* else if (beInGraveyard == true && useRevive == true && Graveyard.transform.childCount == 0)
{
this.transform.SetParent(Hand.transform);
UcanReturn = false;
beInGraveyard = false;
summoningSickness = true;
}*/
}
/* public void ReviveThis()
{
if (beInGraveyard == true && useRevive == true && Graveyard.transform.childCount > 0)
{
Debug.Log("Reviving card");
this.transform.SetParent(Hand.transform);
useRevive = false;
beInGraveyard = false;
summoningSickness = true;
}
else
{
Debug.Log("Revive conditions not met");
Debug.Log("beInGraveyard: " + beInGraveyard);
Debug.Log("useRevive: " + useRevive);
Debug.Log("Graveyard child count: " + Graveyard.transform.childCount);
}
}*/
public void Heal()
{
PlayerHp.staticHp += healXpower;
}
/*public void AttackBoost()
{
power += boostXpower; // Update power first
actualpower = power - hurted; // Update actualpower after modifying power
UpdateUI();
}*/
public void dealxDamage(int x)
{
if (Target != null)
{
if (staticTargetingEnemy = true && stopDealDamage == false && Input.GetMouseButton(0))
{
EnemyHp.staticHp -= damageDealtBySpell;
stopDealDamage = true;
}
}
else
{
foreach (Transform child in EnemyZone.transform)
{
Debug.Log("Attempting to deal damage to AI.");
AICardToHand childAICard = child.GetComponent<AICardToHand>();
if (childAICard.isTarget == true && stopDealDamage == false)
{
childAICard.hurted += damageDealtBySpell; // Adjusting hurted value by the power of the attacking card
stopDealDamage = true;
Debug.Log("Test)");
}
}
}
}
}


Unfortunately, that code didn't work and ended up breaking the deck array, leading to the game-breaking bug. I've removed if (deckData != null) and got the error. ObjectDisposedException: SerializedProperty deck.Array.data[12].thisImage has disappeared!, type is not a supported pptr value UnityEditor.RetainedMode:UpdateSchedulers (), type is not a supported string value UnityEditor.RetainedMode:UpdateSchedulers ().
– Patpig10The goal behind this suggestion to remove
– andrew-lukasik(deckData != null)was to force you, the programmer, to make your program work by design and not by accident. You can add nullcheck back, but do this will clear intent and awareness. Think about other scenarios, like do you even call this method at the right time or in the right way? Maybe do a "filexist"-type of check instead? As this will separate lack of save file ("no save game") from cases whed save data is corrupted - very different cases for which nullcheck is too of a blunt tool to discern between.