using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
using UnityEngine.SceneManagement;
using System;
using UnityStandardAssets.Characters.ThirdPerson;
public class OnGameLoading : MonoBehaviour
{
public CinemachineFreeLook standUpCamera;
public CinemachineFreeLook closeLookCamera;
public CinemachineFreeLook gamePlayCamera;
void Update()
{
// When starting a new game
if (sceneName == "Game" &&
MenuController.LoadSceneForSavedGame == false && newGameStart == false)
{
ThirdPersonUserControl.stop = true;
standUpCamera.m_XAxis.m_MaxSpeed = 0;
standUpCamera.m_YAxis.m_MaxSpeed = 0;
closeLookCamera.m_XAxis.m_MaxSpeed = 0;
closeLookCamera.m_YAxis.m_MaxSpeed = 0;
gamePlayCamera.m_XAxis.m_MaxSpeed = 0;
gamePlayCamera.m_YAxis.m_MaxSpeed = 0;
}
}
}
Is there something easier to access the properties? This way it's working, but isn't it too much code to write or is it fine this way?
I use the advice of 'derHugo, At Least Vision'
Use a dictionary and in this specific use case why not use a method?
public class OnGameLoading : MonoBehaviour
{
public CinemachineFreeLook standUpCamera;
public CinemachineFreeLook closeLookCamera;
public CinemachineFreeLook gamePlayCamera;
public Dictionary<CinemachineCameraType, CinemachineFreeLook> cinemachineFreeLookCameras = new Dictionary<CinemachineCameraType, CinemachineFreeLook>();
private void Awake()
{
cinemachineFreeLookCameras.Add(CinemachineCameraType.standUpCamera, standUpCamera);
cinemachineFreeLookCameras.Add(CinemachineCameraType.closeLookCamera, closeLookCamera);
cinemachineFreeLookCameras.Add(CinemachineCameraType.gamePlayCamera, gamePlayCamera);
}
void Update()
{
// When starting a new game
if (sceneName == "Game" && MenuController.LoadSceneForSavedGame == false && newGameStart == false)
{
ThirdPersonUserControl.stop = true;
standUpCamera.m_XAxis.m_MaxSpeed = 0;
standUpCamera.m_YAxis.m_MaxSpeed = 0;
closeLookCamera.m_XAxis.m_MaxSpeed = 0;
closeLookCamera.m_YAxis.m_MaxSpeed = 0;
gamePlayCamera.m_XAxis.m_MaxSpeed = 0;
gamePlayCamera.m_YAxis.m_MaxSpeed = 0;
// Dictionary foreach
foreach (var item in cinemachineFreeLookCameras.Values)
{
item.m_XAxis.m_MaxSpeed = 0;
item.m_YAxis.m_MaxSpeed = 0;
}
// Dictionary for loop
for (int i = 0; i < cinemachineFreeLookCameras.Count; i++)
{
cinemachineFreeLookCameras.ElementAt(i).Value.m_XAxis.m_MaxSpeed = 0;
cinemachineFreeLookCameras.ElementAt(i).Value.m_YAxis.m_MaxSpeed = 0;
}
// Method
SetFreeLookCameraAxisMaxSpeed(standUpCamera,0,0);
SetFreeLookCameraAxisMaxSpeed(closeLookCamera, 0,0);
SetFreeLookCameraAxisMaxSpeed(gamePlayCamera, 0,0);
}
}
public void SetFreeLookCameraAxisMaxSpeed(CinemachineFreeLook camera,float x,float y)
{
camera.m_XAxis.m_MaxSpeed = x;
camera.m_YAxis.m_MaxSpeed = y;
}
}
public enum CinemachineCameraType
{
standUpCamera,
closeLookCamera,
gamePlayCamera
}
Related
I've begun working on an early alpha menu for my game and I've was wondering how to exclude items in an array, specifically in unity. I'm trying to make every item except the currently used one. I don't know how I should go about it, if anyone could help, that would be amazing.
here's my current code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class CS
{
public List<GameObject> CanvasButtons;
}
public class CanvasSwitcher : MonoBehaviour
{
public List<CS> Screen = new List<CS>();
static int switcher;
public static void ScreenSwitchPlus()
{
switcher += 1;
}
public static void ScreenSwitchMinus()
{
switcher -= 1;
}
public void Update()
{
foreach(GameObject l in Screen[switcher].CanvasButtons)
{
l.SetActive(true);
}
}
}
It would be wiser to use for loop instead of foreach loop here:
public void Update()
{
int ignore = 2;
for(int i = 0; i < Screen[switcher].CanvasButtons.Count; i++)
{
if(i != ignore)
Screen[switcher].CanvasButtons[i].SetActive(true);
else
Screen[switcher].CanvasButtons[i].SetActive(false);
}
}
It could be even shorter without if (admit less readable):
public void Update()
{
int ignore = 2;
for(int i = 0; i < Screen[switcher].CanvasButtons.Count; i++)
{
Screen[switcher].CanvasButtons[i].SetActive(i != ignore);
}
}
... and even shorter with taking CanvasButtons out of loop:
public void Update()
{
int ignore = 2;
var collection = Screen[switcher].CanvasButtons;
for(int i = 0; i < collection.Count; i++)
{
collection[i].SetActive(i != ignore);
}
}
I got it! I was a bit null-brained for a while there, I messed up a few values in the second for statement, but I got it. I'll post the code here. I keep forgetting little things in the math. Like I always say, I don't solve problems, I make them.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class CS
{
public List<GameObject> CanvasButtons;
}
public class CanvasSwitcher : MonoBehaviour
{
public List<CS> Screen = new List<CS>();
static int switcher;
public static void ScreenSwitchPlus()
{
switcher += 1;
}
public static void ScreenSwitchMinus()
{
switcher -= 1;
}
public void FixedUpdate()
{
List<CS> csco = Screen;
for(int i1 = 0; i1 < csco.Count;)
{
List<GameObject> collection = csco[i1].CanvasButtons;
for (int i = 0; i < collection.Count; i++)
{
collection[i].SetActive(i1 == switcher);
switch(i == collection.Count - 1)
{
case true:
i1++;
break;
}
}
}
}
}
I think you are making things too complicated.
It could simply be
public void Update()
{
for(var i = 0; i < Screen.Count; i++)
{
foreach(var button in Screen[i].CanvasButtons)
{
button.SetActive(i == switcher);
}
}
}
Two more points though.
First I would make sure that switcher is actually a valid value. You either want to clamp the value to stay within the index range like
public static void ScreenSwitchPlus()
{
switcher = Mathf.Clamp(switcher + 1, 0, Screen.Count);
}
public static void ScreenSwitchMinus()
{
switcher = Mathf.Clamp(switcher - 1, 0, Screen.Count);
}
or you could implement wrap around at the ends according to your needs like
public static void ScreenSwitchPlus()
{
switcher = (switcher + 1) % Screen.Count;
}
public static void ScreenSwitchMinus()
{
switcher -= 1;
if(switcher < 0) switcher = Screen.Count - 1;
}
and then finally as mentioned I wouldn't do this poll fetching the value in Update every frame at all but rather event driven.
If you really need to (I would claim it is just lazyness ;) ) have that value and methods static you could attach to an event like
private static event Action<int> OnSwitcherChanged;
public static void ScreenSwitchPlus()
{
switcher = (switcher + 1) % Screen.Count;
OnSwitcherChanged?.Invoke(switcher);
}
public static void ScreenSwitchMinus()
{
switcher -= 1;
if(switcher < 0) switcher = Screen.Count - 1;
OnSwitcherChanged?.Invoke(switcher);
}
and then listen to that event like
private void OnEnable()
{
OnSwitcherChanged += HandleSwitchChanged;
}
private void OnDisable()
{
OnSwitcherChanged -= HandleSwitchChanged;
}
private void HandleSwitchChanged(int newIndex)
{
for(var i = 0; i < Screen.Count; i++)
{
foreach(var button in Screen[i].CanvasButtons)
{
button.SetActive(i == switcher);
}
}
}
Try this
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class CS {
public List<GameObject> CanvasButtons;
}
public class CanvasSwitcher : MonoBehaviour {
public List<CS> Screen = new List<CS>();
private static bool m_changed = false;
private static int m_lastSwitcher = 0;
private static int m_switcher = 0;
static int switcher {
get {
return m_switcher;
}
set {
if ( switcher != value ) {
m_lastSwitcher = m_switcher;
m_changed = true;
m_switcher = value;
}
}
}
public static void ScreenSwitchPlus() {
switcher += 1;
}
public static void ScreenSwitchMinus() {
switcher -= 1;
}
private void Update() {
if ( m_changed ) {
UpdateCS();
m_changed = false;
}
}
void UpdateCS() {
if ( m_lastSwitcher < Screen.Count ) {
var canvasBtns = Screen[ m_lastSwitcher ].CanvasButtons;
for ( int i = 0; i < canvasBtns.Count; i++ ) {
canvasBtns[ i ].SetActive( false );
}
}
if ( switcher < Screen.Count ) {
var canvasBtns = Screen[ switcher ].CanvasButtons;
for ( int i = 0; i < canvasBtns.Count; i++ ) {
canvasBtns[ i ].SetActive( true );
}
}
}
}
when i starting my game on the game scene,everything is fine,but when i load from menu,first time is ok,then there is saving data to json,and when i come back to main menu,and then again press play it's " Object reference not set to an instance of an object " for my saveScript which is attached to empty gameObject on game scene.
loading just
SceneManager.LoadSceneAsync("game");
SAVE SCRIPT
public void PopulateSaveData(SaveData sd)
{
//character
sd.s_XP = XP;
respawnScript.instance.PopulateSaveData(sd);
sd.s_x = gameObject.transform.position.x;
sd.s_y = gameObject.transform.position.y;
sd.s_z = gameObject.transform.position.z;
playerHealth.instance.PopulateSaveData(sd);
//sword
playerSword.instance.PopulateSaveData(sd);
//inventory
Inventory.instance.PopulateSaveData(sd);
//sd.s_allItemsPositions = allItemsPositions;
//sd.s_allPotionInteractions = GameObject.FindObjectsOfType<potionInteraction>().ToList();
if (allPotionInteractionO.Count > 0)
{
Debug.Log("ALL POTIONS COUNT " + allPotionInteractionO[0]);
sd.s_allPotionInteractions = allPotionInteractionO;
}
sd.s_allWeaponInteractions = all_swords;
sd.s_allWeaponInteractionsGO = all_swordsGO;
for (int i = 0; i < all_swordsGO.Count; i++)
{
sd.s_allSwordsRotation.Add(all_swordsGO[i].transform.rotation);
}
for (int i = 0; i < all_swordsGO.Count; i++)
{
//because some objects can be destroyed thats why im initializing list again
//allInteractableGameObjects = GameObject.FindGameObjectsWithTag("interactable object").ToList();
// sd.s_allItemsPositions.Add(allInteractableGameObjects[i].transform.position);
sd.s_allSwordsPositions.Add(all_swordsGO[i].transform.position);
}
for (int i = 0; i < allPotionInteractionO.Count; i++)
{
sd.s_allPotionsPositions.Add(allPotionInteractionO[i].transform.position);
}
///going through list and check if there is used item,then saving its bool to another list at same position
for (int i = 0; i < allPotionInteractionO.Count; i++)
{
if (allPotionInteractionO[i].isUsed)
{
allPotionsIsUsed[i] = true;
}
}
sd.s_allPotionsIsUsed = allPotionsIsUsed;
//quest part
for (int i = 0; i < allNPCS.Count; i++)
{
if (allNPCS[i].quest == null)
{
allNpcQuests[i] = null;
}
}
sd.s_allQuests = allNpcQuests;
if(MarieleQuest.instance.currentMarieleQuest!=null)
{
sd.s_currentQuest = MarieleQuest.instance.currentMarieleQuest;
}
foreach (Slot slot in slotsToSave)
{
slot.PopulateSaveData(sd);
}
//enemies
foreach (EnemyStats enemy in all_enemies)
{
enemy.PopulateSaveData(sd);
}
//procedural enemies
foreach (ProceduralStats enemy in all_procedural_enemies)
{
enemy.PopulateSaveData(sd);
}
}
LOAD
public void LoadFromSaveData(SaveData sd)
{
if (SceneManager.GetActiveScene().name == "game")
{
//character
XP = sd.s_XP;
if (sd.s_HP > 0)
{
playerHealth.instance.LoadFromSaveData(sd);
}
else if (sd.s_HP == 0)
{
playerHealth.instance.currentHealth = 100;
}
if (sd.s_respawnObject != null)
{
respawnScript.instance.LoadFromSaveData(sd);
}
if (sd.s_x != 0 && sd.s_y != 0 && sd.s_z != 0)
{
gameObject.transform.position = new Vector3(sd.s_x, sd.s_y, sd.s_z);
}
//sword
if (sd.s_sword != null && sd.s_temp != null && sd.s_currentSword != null && sd.s_currentSwordGO != null)
{
playerSword.instance.LoadFromSaveData(sd);
}
else
{
playerSword.instance.currentSwordGameObject = GameObject.Find("character/mixamorig:Hips/mixamorig:Spine/mixamorig:Spine1/" + playerSword.instance.currentSwordGameObject.name);
playerSword.instance.temp = playerSword.instance.currentSwordGameObject;
}
//potions
if (sd.s_allPotionsIsUsed.Count > 0)
{
allPotionsIsUsed = sd.s_allPotionsIsUsed;
}
//quest
if (sd.s_allQuests.Count > 0)
{
Debug.Log("SD ALL QUESTS" + sd.s_allQuests);
allNpcQuests = sd.s_allQuests;
}
if (sd.s_allQuests.Count > 0)
{
for (int i = 0; i < allNPCS.Count; i++)
{
allNPCS[i].quest = allNpcQuests[i];
}
}
if (sd.s_currentQuest != null)
{
MarieleQuest.instance.currentMarieleQuest = sd.s_currentQuest;
}
if (sd.s_allPotionInteractions.Count > 0)//second pattern in if is changed(FOR REMEMBER)
{
Debug.Log("SD ALL POTIONS > 0");
if (sd.s_allPotionInteractions[0] != null)
{
allPotionInteractionO = sd.s_allPotionInteractions;
}
else
{
allPotionInteractionO = GameObject.FindObjectsOfType<potionInteraction>().ToList();
}
for (int b = 0; b < allPotionInteractionO.Count; b++)
{
allPotionInteractionO[b].isUsed = allPotionsIsUsed[b];
}
for (int i = 0; i < allPotionInteractionO.Count; i++)
{
if (allPotionInteractionO[i].isUsed)
{
allPotionInteractionO[i].gameObject.SetActive(false);
}
}
}
Inventory.instance.LoadFromSaveData(sd);
if (sd.s_allWeaponInteractions.Count > 0)
{
//all_swords = sd.s_allWeaponInteractions;
// all_swordsGO = sd.s_allWeaponInteractionsGO;
for (int i = 0; i < all_swordsGO.Count; i++)
{
if (!Inventory.instance.itemsGameObjects.Contains(all_swordsGO[i])
&& all_swordsGO[i] != playerSword.instance.currentSwordGameObject)
{
all_swordsGO[i].SetActive(true);
all_swordsGO[i].transform.rotation = sd.s_allSwordsRotation[i];
}
}
for (int j = 0; j < sd.s_allSwordsPositions.Count; j++)
{
//Debug.Log(sd.s_allItemsPositions[j] + " " + allInteractableGameObjects[j].name);
all_swordsGO[j].transform.position = sd.s_allSwordsPositions[j];
allPotionInteractionO[j].transform.position = sd.s_allPotionsPositions[j];
}
}
foreach (Slot slot in slotsToSave)
{
slot.LoadFromSaveData(sd);
}
//enemies
foreach (EnemyStats enemy in all_enemies)
{
enemy.LoadFromSaveData(sd);
}
foreach (string id in dead_enemies_ids)
{
SaveData.EnemyData enemyData = new SaveData.EnemyData();
enemyData.e_Health = 0;
enemyData.e_id = id;
sd.enemyData.Add(enemyData);
}
//procedural enemies
foreach (ProceduralStats enemy in all_procedural_enemies)
{
enemy.LoadFromSaveData(sd);
}
foreach (string id in all_procedural_ids)
{
SaveData.ProceduralEnemyData enemyData = new SaveData.ProceduralEnemyData();
enemyData.e_ProcHealth = 0;
enemyData.e_ProcId = id;
sd.proceduralEnemyData.Add(enemyData);
}
}
}
these two scripts just writing data to lists,and reading it from saved file,
saving is called once OnApplicationQuit()
load called at the end of Start()
when i open scene game just from itself and close and load again,everything work fine,because its destroying objects and load them again,but
once i start from main menu,from there do LoadScene("game") i'm getting error that some fields are not exist anymore,but it's like unreal
SaveData script which have all info and store it to file,then read
public class SaveData : MonoBehaviour
{
private void Awake()
{
}
private void Start()
{
s_inventoryGO = new List<GameObject>();
Debug.Log("s_inventoryGO" + s_inventoryGO.Count);
}
//character saving
public int s_XP;
public GameObject s_respawnObject;
public float s_x;
public float s_y;
public float s_z;
//inventory
public List<Item> s_inventory = new List<Item>();
public List<GameObject> s_inventoryGO = new List<GameObject>();
public List<GameObject> s_allGameObjectInventory = new List<GameObject>();
public List<GameObject> s_allInteractableObjects = new List<GameObject>();
public List<potionInteraction> s_allPotionInteractions = new List<potionInteraction>();
public List<weaponInteract> s_allWeaponInteractions = new List<weaponInteract>();
public List<GameObject> s_allWeaponInteractionsGO = new List<GameObject>();
public List<Quaternion> s_allSwordsRotation = new List<Quaternion>();
public List<Vector3> s_allSwordsPositions = new List<Vector3>();
public List<Vector3> s_allPotionsPositions = new List<Vector3>();
public List<bool> s_allPotionsIsUsed = new List<bool>();
public List<Quest> s_allQuests = new List<Quest>();
public Quest s_currentQuest;
public int s_HP;
[System.Serializable]
public struct SlotsData
{
public Item s_slotItem;
public string s_id;
//public Sprite s_icon ;
}
public List<SlotsData> s_slots = new List<SlotsData>();
//sword
public Transform s_sword;
public GameObject s_currentSwordGO;
public GameObject s_temp;
public swordEquipping s_currentSword;
//enemy saving
[System.Serializable]
public struct EnemyData
{
public int e_Health;
public string e_id;
}
public List<EnemyData> enemyData = new List<EnemyData>();
//procedural enemy saving
[System.Serializable]
public struct ProceduralEnemyData
{
public int e_ProcHealth;
public string e_ProcId;
}
public List<ProceduralEnemyData> proceduralEnemyData = new List<ProceduralEnemyData>();
public string toJson()
{
return JsonUtility.ToJson(this);
}
public void LoadFromJson(string json)
{
JsonUtility.FromJsonOverwrite(json, this);
}
}
When using DontDestroyOnLoad wherever you want this object to exist, make a copy of it in your scene if you want the data stored to persist between your game session.
Here is a snippet from the docs
void Awake()
{
GameObject[] objs = GameObject.FindGameObjectsWithTag("music");
if (objs.Length > 1)
{
Destroy(this.gameObject);
}
DontDestroyOnLoad(this.gameObject);
}
It will search for other objects in the scene with the same tag. If it finds it, it will destroy itself. What you can do here is have a public Init() function on your script. When a new scene is loaded with the object and your object already finds an instance of itself, it can pass the local references to the existing object. Something like...
public GameObject objRef1;
public GameObject objRef2;
public void Init(GameObject obj1, GameObject obj2)
{
objRef1 = obj1;
objRef2 = obj2;
...
etc.
}
Inside of the Awake() of the new object, you would call the existing objects Init with the local references it has, which work as it loaded with your scene.
void Awake()
{
// make the tag unique so you only grab objects of this save type
GameObject[] objs = GameObject.FindGameObjectsWithTag("yourObjectsTag");
if (objs.Length > 1)
{
objs[0].GetComponent<YourScriptName>().Init(obj1, obj2, ..., etc.);
Destroy(this.gameObject);
}
DontDestroyOnLoad(this.gameObject);
}
In this approach it means you have a local copy of your DontDestroyOnLoad object in every scene so when the existing one loads in, it can just grab the references from it.
In the SaveTransform method I'm saving all the changes to the hard disk:
PlayerPrefs.Save();
But then when using a break point in the LoadTransform method I see that the parent/s are null.
loadedTransforms[i].parent = savedTransforms[i].parent;
savedTransforms[i].parent is null.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine.SceneManagement;
public static class TransformSaver
{
[System.Serializable]
public class TransformInfo
{
public string sceneName;
public string name;
public Transform parent;
public Vector3 pos;
public Quaternion rot;
public Vector3 scale;
}
//Save Transform
public static void SaveTransform(Transform[] tranformToSave)
{
TransformInfo[] trnfrm = new TransformInfo[tranformToSave.Length];
for (int i = 0; i < trnfrm.Length; i++)
{
trnfrm[i] = new TransformInfo();
trnfrm[i].sceneName = tranformToSave[i].gameObject.scene.name;
trnfrm[i].name = tranformToSave[i].name;
trnfrm[i].parent = tranformToSave[i].parent;
trnfrm[i].pos = tranformToSave[i].localPosition;
trnfrm[i].rot = tranformToSave[i].localRotation;
trnfrm[i].scale = tranformToSave[i].localScale;
}
string jsonTransform = JsonHelper.ToJson(trnfrm, true);
PlayerPrefs.SetString("transform", jsonTransform);
PlayerPrefs.Save();
}
//Load Transform
public static Transform[] LoadTransform()
{
string jsonTransform = PlayerPrefs.GetString("transform");
if (jsonTransform == null)
{
return null;
}
TransformInfo[] savedTransforms = JsonHelper.FromJson<TransformInfo>(jsonTransform);
GameObject[] gameObjects = new GameObject[savedTransforms.Length];
Transform[] loadedTransforms = new Transform[savedTransforms.Length];
for (int i = 0; i < gameObjects.Length; i++)
{
SceneManager.SetActiveScene(SceneManager.GetSceneByName(savedTransforms[i].sceneName));
gameObjects[i] = new GameObject();
loadedTransforms[i] = gameObjects[i].transform;
loadedTransforms[i].name = savedTransforms[i].name;
loadedTransforms[i].parent = savedTransforms[i].parent;
loadedTransforms[i].localPosition = savedTransforms[i].pos;
loadedTransforms[i].localRotation = savedTransforms[i].rot;
loadedTransforms[i].localScale = savedTransforms[i].scale;
}
return loadedTransforms;
}
}
This is how I'm using the methods:
private void SaveLoad()
{
if (GUILayout.Button("Save"))
{
var selected = Selection.objects.OfType<GameObject>().ToList();
if (selected.Count > 0)
{
for (var i = selected.Count - 1; i >= 0; --i)
{
var select = selected[i];
transformSelection.Add(select.transform);
}
TransformSaver.SaveTransform(transformSelection.ToArray());
tempSelections = transformSelection;
transformSelection = new List<Transform>();
}
}
if (GUILayout.Button("Load"))
{
TransformSaver.LoadTransform();
}
}
Transforms can't be serialized
(But you knew that, which is why you created this class)
Yet:
public Transform parent;
...
trnfrm[i].parent = tranformToSave[i].parent;
You're still trying to serialize a Transform!
Rather than trying to serialize a transform in this manner (child-up) how about serializing a different way? If a transform has children create an array of TransformInfos and stuff the transform's children into it (parent-down).
It should also be noted that PlayerPrefs isn't meant for this kind of data. It's stored in plain text which the user can easily find and edit freely, and has a very limited size.
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 5 years ago.
thanks for reading, I am working on a small memory card game in C# using Unity. When I run a certain scene I am receiving constant errors.
The errors are as follows:
"NullReferenceException: Object reference not set to an instance of an object
Card.SetUpArt () (at Assets/Scripts/Card.cs:31)
Pairs.SetUpDeck () (at Assets/Scripts/Pairs.cs:62)
Pairs.Update () (at Assets/Scripts/Pairs.cs:23)"
My code is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class Card : MonoBehaviour {
public static bool NO_TURN = false;
[SerializeField]
private int cardState; //state of card
[SerializeField]
private int cardNumber; //Card value (1-13)
[SerializeField]
private bool _setUp = false;
private Sprite cBack; //card back (Green square)
private Sprite cFace; //card face (1-10 JQKA)
private GameObject pairsManager;
void Begin()
{
cardState = 1; //cards face down
pairsManager = GameObject.FindGameObjectWithTag("PairsManager");
}
public void SetUpArt()
{
cBack = pairsManager.GetComponent<Pairs>().GetBack(); //<--error
cFace = pairsManager.GetComponent<Pairs>().GetFace(cardNumber);
turnCard();//turns the card
}
public void turnCard() //handles turning of card
{
if (cardState == 0)
{
cardState = 1;
}
else if(cardState == 1)
{
cardState = 0;
}
if (cardState == 0 && !NO_TURN)
{
GetComponent<Image>().sprite = cBack; // shows card back
}
else if (cardState == 1 && !NO_TURN)
{
GetComponent<Image>().sprite = cFace; // shows card front
}
}
//setters and getters
public int Number
{
get {return cardNumber;}
set { cardNumber = value;}
}
public int State
{
get { return cardState; }
set { cardState = value; }
}
public bool SetUp
{
get { return _setUp; }
set { _setUp = value; }
}
public void PairCheck()
{
StartCoroutine(pause ());
}
IEnumerator pause()
{
yield return new WaitForSeconds(1);
if (cardState == 0)
{
GetComponent<Image>().sprite = cBack;
}
else if (cardState == 1)
{
GetComponent<Image>().sprite = cFace;
}
}
}
And:
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEngine;
public class Pairs : MonoBehaviour {
public Sprite[] cardFace; //array of card faces
public Sprite cardBack;
public GameObject[] deck; //array of deck
public Text pairsCount;
private bool deckSetUp = false;
private int pairsLeft = 13;
// Update is called once per frame
void Update () {
if (!deckSetUp)
{
SetUpDeck();
}
if (Input.GetMouseButtonUp(0)) //detects left click
{
CheckDeck();
}
}//Update
void SetUpDeck()
{
for(int i = 0; i <deck.Length; i++)//resets cards
{
deck[i].GetComponent<Card>().SetUp = false;
}
for (int ix = 0; ix < 2; ix++) //sets up cards twice,
{
for(int i = 1; i < 14; i++)//sets up card value (2-10 JQKA)
{
bool test = false;
int val = 0;
while (!test)
{
val = Random.Range(0, deck.Length);
test = !(deck[val].GetComponent<Card>().SetUp);
}//while
//sets up cards
deck[val].GetComponent<Card>().Number = i;
deck[val].GetComponent<Card>().SetUp = true;
}//nested for
}//for
foreach (GameObject crd in deck)
{
crd.GetComponent<Card>().SetUpArt();
}
if (!deckSetUp)
{
deckSetUp = true;
}
}//SetUpDeck
public Sprite GetBack()
{
return cardBack;
}//getBack
public Sprite GetFace(int i)
{
return cardFace[i - 1];
}//getFace
void CheckDeck()
{
List < int > crd = new List<int>();
for(int i = 0; i < deck.Length; i++)
{
if(deck[i].GetComponent<Card>().State == 1)
{
crd.Add(i);
}
}
if(crd.Count == 2)
{
CompareCards(crd);
}
}//CheckDeck
void CompareCards(List<int> crd)
{
Card.NO_TURN = true; //stops cards turning
int x = 0;
if(deck[crd[0]].GetComponent<Card>().Number ==
deck[crd[1]].GetComponent<Card>().Number)
{
x = 2;
pairsLeft--;
pairsCount.text = "PAIRS REMAINING: " + pairsLeft;
if(pairsLeft == 0) // goes to home screen when game has been won
{
SceneManager.LoadScene("Home");
}
}
for(int j = 0; j < crd.Count; j++)
{
deck[crd[j]].GetComponent<Card>().State = x;
deck[crd[j]].GetComponent<Card>().PairCheck();
}
}//CompareCards
}
Any help anyone can offer would be greatly appreciated. Thank you in advance.
Link to GitHub Repository
I don't have knowledge about C#, as I'm working with java. You should initialize your variables. For more information I found this link What is a NullReferenceException, and how do I fix it?
I have a dictionary with gameobjects as the keys, which is n amount and gameobjects as the values, which is amount of possible 4.
Dictionary<GameObject, ArrayList> polesAttachedToFloor = new Dictionary<GameObject, ArrayList>();
public void AddFloor(GameObject floor)
{
if(floor != null)
{
polesAttachedToFloor.Add(floor, new ArrayList { null,null,null,null });
}
}
public void AddPole(GameObject floor, GameObject pole)
{
for (int i = 0; i <= 4; i++)
{
}
}
How do I iterate through the "values?"... and is there a more 'appropriate' way of doing what Im aiming for?
ArrayList poles;
if (polesAttachedToFloor.ContainsKey(floor))
{
poles = dictionary[floor];
}
if(poles!=null)
{
for (int i = 0; i <= 4; i++)
{
poles.Add(pole);
}
}
Try that inside you AddPole function.
There is how you should encapsulate that...Dont have unity running so may be some typos.
public class FloorManager:MonoBehaviour
{
public gameObject floorPrefab;
private List<Floor> floors;
void Start()
{
floors = new List<Floor>();
}
public void AddFloor()
{
//instantiate prefab // gameObject floorGo = Instantiate....
Floor floorScript = floorGo.getComponent<Floor>();
floors.Add(floorScript);
floorScript.AddPoles();
}
public void RemoveFloor(Floor floor)
{
floors[floors.IndexOf(floor)].gameObject.Destory();
floors.Remove(floor);
}
}
public class Floor : MonoBehaviour
{
public gameObject polePrefab;
public Pole [] poles = new Pole[4];
public void AddPoles()
{
for (int i = 0; i < 4; i++)
{
//instantiate prefab // gameObject poleGo = Instantiate....
Pole poleScript = poleGo.getComponent<Pole>();
poles[i]=poleScript;
}
}
}
public class Pole : MonoBehaviour
{
//some logic here if needed...Destroy...Damage...
}
Play with Enumerator :D Have fun
public void AddPole(GameObject floor, GameObject pole)
{
var enumerator = polesAttachedToFloor.GetEnumerator ();
for (int i = 0; i <= 4; i++)
{
if (enumerator.MoveNext ()) {
var item = enumerator.Current;
}
}
}