hi guys im currently messing around making a card game and im using a insertion sort on a array that holds a struct containing a transform, vector3’s and a int. if i keep my insertion sort in the main body of GameStart() i receive no errors but i wanted to extract it to its own method so i can re use it(currently im using random range to set the player order but in the event of the tie i would like to extract the tied players and then re generate a range so i can re insert them back into the original array in the correct tie broken order while maintaining the order of the first players).after i extract it to its own method then i get this error from unity
ArgumentNullException: Value cannot be null.
Parameter name: _unity_self
UnityEditor.SerializedObject.FindProperty (System.String propertyPath) (at <fd50159aad624335967647b443372e50>:0)
UnityEditor.UIElements.Bindings.SerializedObjectBindingContext.BindPropertyRelative (UnityEngine.UIElements.IBindable field, UnityEditor.SerializedProperty parentProperty) (at <cbf1e1731e9f4cb9979d9405a8eaa15c>:0)
UnityEditor.UIElements.Bindings.SerializedObjectBindingContext.BindTree (UnityEngine.UIElements.VisualElement element, UnityEditor.SerializedProperty parentProperty) (at <cbf1e1731e9f4cb9979d9405a8eaa15c>:0)
UnityEditor.UIElements.Bindings.SerializedObjectBindingContext.ContinueBinding (UnityEngine.UIElements.VisualElement element, UnityEditor.SerializedProperty parentProperty) (at <cbf1e1731e9f4cb9979d9405a8eaa15c>:0)
UnityEditor.UIElements.Bindings.DefaultSerializedObjectBindingImplementation+BindingRequest.Bind (UnityEngine.UIElements.VisualElement element) (at <cbf1e1731e9f4cb9979d9405a8eaa15c>:0)
UnityEngine.UIElements.VisualTreeBindingsUpdater.Update () (at <0a07728b89ae49bcb53a2d3d7c56983c>:0)
UnityEngine.UIElements.VisualTreeUpdater.UpdateVisualTreePhase (UnityEngine.UIElements.VisualTreeUpdatePhase phase) (at <0a07728b89ae49bcb53a2d3d7c56983c>:0)
UnityEngine.UIElements.Panel.UpdateBindings () (at <0a07728b89ae49bcb53a2d3d7c56983c>:0)
UnityEngine.UIElements.UIElementsUtility.UnityEngine.UIElements.IUIElementsUtility.UpdateSchedulers () (at <0a07728b89ae49bcb53a2d3d7c56983c>:0)
UnityEngine.UIElements.UIEventRegistration.UpdateSchedulers () (at <0a07728b89ae49bcb53a2d3d7c56983c>:0)
UnityEditor.RetainedMode.UpdateSchedulers () (at <cbf1e1731e9f4cb9979d9405a8eaa15c>:0)
i cant see the unity messages in side of visual studio while the debugger is attached and while debugger is attached it seems to run through my entire code correctly so im not sure where the error is coming from
my array is being sorted correctly weather my function is extracted or in the main body so im not sure where the _unity_self null reference is coming from as it doesnt actually let me double click it or give me the line number that its happening at either
i have attached my entire code GameStart() is initally called on line 45 at the end of start and the actual GameStart() funtion is on line 183 the shuffling function and its companion function take up alot of lines of code(i didnt want sudo random and was playing with arrays) also attached a zipfile of the entire project if that may be better to look at… code below
using System;
using System.Collections;
using System.Linq;
using UnityEngine;
public class DeckHandler : MonoBehaviour
{
public GameObject discardPile;
public Dealer dealerScript;
public Sprite[] sprites;
private Sprite[] cards;
private int cardIndex = 0;
private CardSprites cardSprites;
private bool swap = false;
public int shuffleCount;
private int _shuffleCount;
// Start is called before the first frame update
void Start()
{
_shuffleCount = shuffleCount;
cards = new Sprite[sprites.Length - 1];
if (PlayerPrefs.HasKey("Has_deck"))
{
if (PlayerPrefs.GetInt("Has_deck") == 1)
{
Debug.Log("deck exists");
string cardsArray = PlayerPrefs.GetString("shuffled_deck");//get the deck from playerprefs
cardSprites = JsonUtility.FromJson<CardSprites>(cardsArray);
for (int i = 0; i < cards.Length; i++)
{
cards[i] = cardSprites.deckEntrys[i].cardSprite;
//Debug.Log("cards[" + i + "] = " + cards[i]);
}
cardSprites = null;
}
}
else // create a new deck and shuffle it.
{
Array.Copy(sprites, 1, cards, 0, cards.Length);
shuffle(cards);
PlayerPrefs.SetInt("Has_deck", 1);
cardSprites = null;
}
gameStart();
}
// Update is called once per frame
void Update()
{
}
void shuffle(Sprite[] cards)
{
if (_shuffleCount <= 0)
{ //fully shuffled reset shoffle count to default and return
//_shuffleCount = shuffleCount;
SaveDeck();
return;
}
int half = cards.Length / 2;
Sprite[] tempSprites = new Sprite[cards.Length];
Sprite[] spriteArrA = new Sprite[half];
Sprite[] spriteArrB = new Sprite[half];
Array.Copy(cards, spriteArrA, half);
Array.Copy(cards, half, spriteArrB, 0, half);
for (int a = 0, b = 0, i = 0; i < tempSprites.Length; i++)
{
shuffler(spriteArrA, spriteArrB, tempSprites, ref i, ref a, ref b, ref swap);//ref is c# version of a pointer
}
Array.Copy(tempSprites, cards, cards.Length);
// take the new Array that has been shuffled once and split it into 6
int sixth = cards.Length / 6;
spriteArrA = new Sprite[sixth];
spriteArrB = new Sprite[sixth];
Sprite[] spriteArrC = new Sprite[sixth];
Sprite[] spriteArrD = new Sprite[sixth];
Sprite[] spriteArrE = new Sprite[sixth];
Sprite[] spriteArrF = new Sprite[sixth];
Array.Copy(cards, spriteArrA, sixth);
Array.Copy(cards, sixth, spriteArrB, 0, sixth);
Array.Copy(cards, sixth * 2, spriteArrC, 0, sixth);
Array.Copy(cards, sixth * 3, spriteArrD, 0, sixth);
Array.Copy(cards, sixth * 4, spriteArrE, 0, sixth);
Array.Copy(cards, sixth * 5, spriteArrF, 0, sixth);
//shuffle thoes 6 into 3
int third = cards.Length / 3;
Sprite[] spriteArrG = new Sprite[third];//a>d
Sprite[] spriteArrH = new Sprite[third];//c>f
Sprite[] spriteArrI = new Sprite[third];//b>e
for (int count = 0, a = 0, b = 0, i = 0; i < third; i++)
{
if (count == 0)
{
shuffler(spriteArrA, spriteArrD, spriteArrG, ref i, ref a, ref b, ref swap);
if (i == third - 1)
{
a = 0;
b = 0;
i = -1;//-1 because loop will incriment it to 1 if set at 0
count++;
}
}
else if (count == 1)
{
shuffler(spriteArrC, spriteArrF, spriteArrH, ref i, ref a, ref b, ref swap);
if (i == third - 1)
{
a = 0;
b = 0;
i = -1;
count++;
}
}
else
{
shuffler(spriteArrB, spriteArrE, spriteArrI, ref i, ref a, ref b, ref swap);
}
}
//shuffel two thirds into each other
int twoThirds = third * 2;
Sprite[] spriteArrJ = new Sprite[twoThirds];
for (int i = 0, a = 0, b = 0; i < twoThirds; i++)
{
shuffler(spriteArrG, spriteArrH, spriteArrJ, ref i, ref a, ref b, ref swap);
}
//copy back into origonal Arrays
Array.Copy(spriteArrJ, spriteArrG, third);
Array.Copy(spriteArrJ, third, spriteArrH, 0, third);
//reshuffel shuffeled Array into non-shuffled(semi shuffeled?) Array
for (int i = 0, a = 0, b = 0; i < twoThirds; i++)
{
shuffler(spriteArrH, spriteArrI, spriteArrJ, ref i, ref a, ref b, ref swap);
}
Array.Copy(spriteArrJ, spriteArrH, third);
Array.Copy(spriteArrJ, third, spriteArrI, 0, third);
tempSprites = spriteArrG.Concat(spriteArrH).Concat(spriteArrI).ToArray();//join shuffled Arrays back together
//cut the deck b over a
spriteArrA = new Sprite[half];
spriteArrB = new Sprite[half];
Array.Copy(tempSprites, spriteArrA, half);
Array.Copy(tempSprites, half, spriteArrB, 0, half);
tempSprites = spriteArrB.Concat(spriteArrA).ToArray();
Array.Copy(tempSprites, cards, cards.Length);
// use recursion to reshuffle shuffled Array
_shuffleCount--;
shuffle(cards);
}
void shuffler(Sprite[] sourceA, Sprite[] sourceB, Sprite[] destination, ref int i, ref int a, ref int b, ref bool swap)
{
if (!swap)
{
//add spritesArrA to Sprites[0]
destination[i] = sourceA[a];
a++;
swap = true;
}
else
{
//add spritesArrB to Sprites[1]
destination[i] = sourceB[b];
b++;
swap = false;
}
}
[System.Serializable]
private struct Players
{
public Transform playerTransform;
public Vector3[] hand;
public int order;
};
[SerializeField] private Players[] players;
private GameObject playersContainer;
private int maxPlayers = 6;
private int playerCount;
private int handCount;
private float offset;
void gameStart()
{
//get the player container
playersContainer = GameObject.FindWithTag("Players");
//count the active children
for (int i = 0; i < maxPlayers; i++)
{
if (playersContainer.transform.GetChild(i).gameObject.activeSelf)
{
playerCount++;
}
}
//initiate player array
players = new Players[playerCount];
//calculate starting card count and first card offset
if (playerCount < 3)
{
handCount = 9;
offset = -4.0f * .8f;
}
else if (playerCount >= 3 && playerCount <= 5)
{
handCount = 7;
offset = -3.0f * .8f;
}
else
{
handCount = 5;
offset = -2.0f * .8f;
}
for (int i = 0; i < playerCount; i++)
{
players[i].hand = new Vector3[handCount];
}
//populate player array
for (int i = 0; i < playerCount; i++)
{
players[i].order = UnityEngine.Random.Range(0, 21);
string currentPlayer = "Player" + (i + 1).ToString();
players[i].playerTransform = playersContainer.transform.Find(currentPlayer);
//Debug.Log(currentPlayer + "position = " + players[i].playerTransform.position);
float _offset = offset;
for (int j = 0; j < handCount; j++)
{
Vector3 playerVector = GetVector(i, _offset);
players[i].hand[j] = new Vector3(playerVector.x, playerVector.y, playerVector.z);
_offset += .8f;
}
}
//sort array
SortArray(players);
/*
for (int i = 1; i < playerCount; i++)
{
Players currentPlayer = players[i];//get current player
int previousElement = i - 1;//calculate previous elements position in array
int currentValue = players[i].order;//get current elements value
int previousValue = players[previousElement].order;//get previous elements value
while (previousElement >= 0 && previousValue > currentValue)//while we are not less the first element and the
//previous value is greater then the current value
{
players[previousElement + 1] = players[previousElement];//set the next element to the previous element
previousElement--;//note new position of previous element
if (previousElement >= 0)
{
previousValue = players[previousElement].order;
}
}
players[previousElement + 1] = currentPlayer;//set the next element to the current element
}
*/
//deal starting hand to each player
for (int i = 0; i < playerCount; i++)
{
for (int j = 0; j < handCount; j++)
{
dealerScript.dealCard(players[i].hand[j], cards[cardIndex], players[i].playerTransform);
cardIndex++;
}
}
//deal first card
Vector3 discardPosition = discardPile.transform.position;
dealerScript.dealCard(discardPosition, cards[cardIndex], discardPile.transform);
cardIndex++;
}
Vector3 GetVector(int i, float _offset)
{
Vector3 calculatedVector;
if (players[i].playerTransform.position.y < 0)
{
calculatedVector = players[i].playerTransform.position + (Vector3.right * _offset);
}
else
{
calculatedVector = players[i].playerTransform.position + (Vector3.left * _offset);
}
return calculatedVector;
}
void SortArray(Players[] array)
{
//sort player array using a insertion sort algorithm https://www.geeksforgeeks.org/insertion-sort/
for (int i = 1; i < array.Length; i++)
{
Players currentPlayer = array[i];//get current player
int previousElement = i - 1;//calculate previous elements position in array
int currentValue = array[i].order;//get current elements value
int previousValue = array[previousElement].order;//get previous elements value
while (previousElement >= 0 && previousValue > currentValue)//while we are not less the first element and the
//previous value is greater then the current value
{
array[previousElement + 1] = array[previousElement];//set the next element to the previous element
previousElement--;//note new position of previous element
if (previousElement >= 0)
{
previousValue = array[previousElement].order;
}
}
array[previousElement + 1] = currentPlayer;//set the next element to the current element
}
return;
/*
void sort(int[] arr)
{
int n = arr.Length;
for (int i = 1; i < n; ++i)
{
int key = arr[i];
int j = i - 1;
// Move elements of arr[0..i-1],
// that are greater than key,
// to one position ahead of
// their current position
while (j >= 0 && arr[j] > key)
{
arr[j + 1] = arr[j];
j = j - 1;
}
arr[j + 1] = key;
}
}
*/
}
void SaveDeck()
{
cardSprites = new CardSprites(cards);//populate class to save to json
string jsonString = JsonUtility.ToJson(cardSprites);
cardSprites = null;//release memory
Debug.Log("json string = " + jsonString);
PlayerPrefs.SetString("shuffled_deck", jsonString);
PlayerPrefs.Save();
}
[System.Serializable]
public class DeckEntry
{
public Sprite cardSprite;
public string cardName;
}
[System.Serializable]
public class CardSprites
{
public DeckEntry[] deckEntrys;
public CardSprites(Sprite[] cards)
{
deckEntrys = new DeckEntry[cards.Length];
for (int i = 0; i < cards.Length; i++)
{
deckEntrys[i] = new DeckEntry
{
cardSprite = cards[i],
cardName = cards[i].name
};
Debug.Log("added");
}
}
}
}