Forum begins after the advertisement:
[Part 12] Nullreference of SoilManager
Home › Forums › Video Game Tutorial Series › Creating a Farming RPG in Unity › [Part 12] Nullreference of SoilManager
- This topic has 10 replies, 2 voices, and was last updated 4 days, 20 hours ago by Jhan Khendrick Perez.
-
AuthorPosts
-
December 13, 2024 at 4:33 pm #16752::
Good Afternoon
I am having problem in regarding the saving of FarmData and CropData, the rest is working. Is this because of a bad arrangement in the Hierarchy? My SoilManager is placed in the PlantingArea gameobject, and the error NullReference is being point in on the Line 73 of my Code
View post on imgur.com
December 13, 2024 at 4:33 pm #16753December 13, 2024 at 6:13 pm #16756::For Reference this is what my SoilSaveState look like, CropSaveState and SoilManager
SoilSaveState
[System.Serializable] public struct SoilSaveState { public PottingSoil.SoilStatus soilStatus; public GameTimeStamp lastWatered; public SoilSaveState(PottingSoil.SoilStatus soilStatus, GameTimeStamp lastWatered) { this.soilStatus = soilStatus; this.lastWatered = lastWatered; } }
CropSaveState
[System.Serializable] public struct CropSaveState { public int soilID; public string seedToGrow; public NewCropBehaviour.CropState cropState; public int growth; public int health; public CropSaveState(int soilID, string seedToGrow, NewCropBehaviour.CropState cropState, int growth, int health) { this.soilID = soilID; this.seedToGrow = seedToGrow; this.cropState = cropState; this.growth = growth; this.health = health; } }
SoilManager
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class SoilManager : MonoBehaviour { public static SoilManager Instance { get; private set; } public static Tuple<List<SoilSaveState>, List<CropSaveState>> urbanFarmData = null; public GameObject[] plantingAreas; List<PottingSoil> soilPlots = new List<PottingSoil>(); List<SoilSaveState> soilData = new List<SoilSaveState>(); List<CropSaveState> cropData = new List<CropSaveState>(); private void Awake() { if (Instance != null && Instance != this) { Destroy(this); } else { Instance = this; } } private void OnEnable() { RegisterSoilPlots(); StartCoroutine(LoadFarmData()); } IEnumerator LoadFarmData() { yield return new WaitForEndOfFrame(); if (urbanFarmData != null) { //Load any save data ImportSoilData(urbanFarmData.Item1); ImportCropData(urbanFarmData.Item2); } } private void OnDestroy() { urbanFarmData = new Tuple<List<SoilSaveState>, List<CropSaveState>>(soilData, cropData); cropData.ForEach((CropSaveState crop) => { Debug.Log(crop.seedToGrow); }); } #region Register and Deregistering void RegisterSoilPlots() { foreach (GameObject plantingArea in plantingAreas) { foreach (Transform soilTransform in plantingArea.transform) { PottingSoil potSoil = soilTransform.GetComponent<PottingSoil>(); if (potSoil != null) { soilPlots.Add(potSoil); soilData.Add(new SoilSaveState()); potSoil.id = soilPlots.Count - 1; // Assign unique ID } } } Debug.Log($"Registered {soilPlots.Count} soil plots across {plantingAreas.Length} planting areas."); } //Registers the crop onto the Instance public void RegisterCrop(int landID, SeedData seedToGrow, NewCropBehaviour.CropState cropState, int growth, int health) { cropData.Add(new CropSaveState(landID, seedToGrow.name, cropState, growth, health)); } public void DeregisterCrop(int soilID) { cropData.RemoveAll(x => x.soilID == soilID); } #endregion #region State Changes //Update the corresponding Soil Data on ever change to the soil's state public void OnSoilStateChange(int id, PottingSoil.SoilStatus soilStatus, GameTimeStamp lastWatered) { soilData[id] = new SoilSaveState(soilStatus, lastWatered); } public void OnCropStateChange(int soilID, NewCropBehaviour.CropState cropState, int growth, int health) { int cropIndex = cropData.FindIndex(x => x.soilID == soilID); if (cropIndex == -1) { Debug.LogError($"No crop found with landID {soilID}"); return; } string seedToGrow = cropData[cropIndex].seedToGrow; cropData[cropIndex] = new CropSaveState(soilID, seedToGrow, cropState, growth, health); } #endregion #region LoadingData public void ImportSoilData(List<SoilSaveState> soilDatasetToLoad) { for(int i = 0; i < soilDatasetToLoad.Count; i++) { SoilSaveState soilDataToLoad = soilDatasetToLoad[i]; soilPlots[i].LoadSoilData(soilDataToLoad.soilStatus, soilDataToLoad.lastWatered); } soilData = soilDatasetToLoad; } public void ImportCropData(List<CropSaveState> cropDatasetToLoad) { cropData = cropDatasetToLoad; foreach (CropSaveState cropSave in cropDatasetToLoad) { PottingSoil soilToPlant = soilPlots[cropSave.soilID]; NewCropBehaviour cropToPlant = soilToPlant.SpawnCrop(); Debug.Log(cropToPlant.gameObject); SeedData seedToGrow = (SeedData)NewInventoryManager.Instance.itemIndex.GetItemFromString(cropSave.seedToGrow); cropToPlant.LoadCrop(cropSave.soilID, seedToGrow, cropSave.cropState, cropSave.growth, cropSave.health); } } #endregion }
December 14, 2024 at 10:28 am #16769December 14, 2024 at 12:39 pm #16770::GameStateManager
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class GameStateManager : MonoBehaviour { public static GameStateManager Instance { get; private set; } public Image fadeImage; public float fadeDuration = 1.0f; private void Awake() { if (Instance != null && Instance != this) { Destroy(this); } else { Instance = this; } } public void Sleep() { GameTimeStamp timestampOfNextDay = TimeManager.Instance.GetGameTimeStamp(); timestampOfNextDay.day += 1; timestampOfNextDay.hour = 6; timestampOfNextDay.minute = 0; Debug.Log(timestampOfNextDay.day + " " + timestampOfNextDay.hour + ":" + timestampOfNextDay.minute); TimeManager.Instance.SkipTime(timestampOfNextDay); SaveManager.Save(ExportSaveState()); StartCoroutine(FadeInOut()); } private IEnumerator FadeInOut() { fadeImage.gameObject.SetActive(true); yield return StartCoroutine(Fade(0, 1)); yield return new WaitForSeconds(0.5f); yield return StartCoroutine(Fade(1, 0)); fadeImage.gameObject.SetActive(false); } private IEnumerator Fade(float startAlpha, float endAlpha) { float elapsedTime = 0f; Color color = fadeImage.color; while (elapsedTime < fadeDuration) { elapsedTime += Time.deltaTime; float alpha = Mathf.Lerp(startAlpha, endAlpha, elapsedTime / fadeDuration); fadeImage.color = new Color(color.r, color.g, color.b, alpha); yield return null; } fadeImage.color = new Color(color.r, color.g, color.b, endAlpha); } public GameSaveState ExportSaveState() { //Retrieving the Farm Data List<SoilSaveState> soilData = SoilManager.urbanFarmData.Item1; List<CropSaveState> cropData = SoilManager.urbanFarmData.Item2; //Retrieving the Inventory Data ItemSlotData[] storageSlots = NewInventoryManager.Instance.GetInventorySlots(NewInventorySlot.InventoryType.Storage); ItemSlotData[] harvestlots = NewInventoryManager.Instance.GetInventorySlots(NewInventorySlot.InventoryType.Harvest); ItemSlotData equippedStorageSlot = NewInventoryManager.Instance.GetEquippedSlot(NewInventorySlot.InventoryType.Storage); ItemSlotData equippedHarvestSlot = NewInventoryManager.Instance.GetEquippedSlot(NewInventorySlot.InventoryType.Harvest); //Time GameTimeStamp timestamp = TimeManager.Instance.GetGameTimeStamp(); return new GameSaveState(soilData, cropData, storageSlots, harvestlots, equippedStorageSlot, equippedHarvestSlot, timestamp); } }
GameSaveState
using System.Collections; using System.Collections.Generic; using UnityEngine; [System.Serializable] public class GameSaveState { //Farming Data public List<SoilSaveState> soilData; public List<CropSaveState> cropData; //Inventory public ItemSlotData[] storageSlot; public ItemSlotData[] harvestSlot; public ItemSlotData equippedStorageSlot; public ItemSlotData equippedHarvestSlot; //Time public GameTimeStamp timestamp; public GameSaveState(List<SoilSaveState> soilData, List<CropSaveState> cropData, ItemSlotData[] storageSlot, ItemSlotData[] harvestSlot, ItemSlotData equippedStorageSlot, ItemSlotData equippedHarvestSlot, GameTimeStamp timestamp) { this.soilData = soilData; this.cropData = cropData; this.storageSlot = storageSlot; this.harvestSlot = harvestSlot; this.equippedStorageSlot = equippedStorageSlot; this.equippedHarvestSlot = equippedHarvestSlot; this.timestamp = timestamp; } }
December 14, 2024 at 1:33 pm #16771December 14, 2024 at 1:35 pm #16772December 14, 2024 at 2:02 pm #16773::Ah you can ignore this bug for now and continue following the series, it gets fixed later on. The cause is because you sleep before the variables were initialised. If you were to load into the Farm Scene and went back to your home to sleep this error would not trigger.
Make sure that the lines you commented out are uncommented because it is needed to save the game!
has upvoted this post. December 14, 2024 at 2:04 pm #16774::Will this also work even though I am only playing in one scene, since I am doing it like an urban farming in which I am farming inside my house?
December 14, 2024 at 2:10 pm #16775::If you want it to work in one scene you have to move everything in the OnDestroy function to a new function and have it called every time the land or crop state is updated. Right now it is designed to only save your changes globally after you leave the farm scene.
Alternatively, you can just get rid of the urbanFarmData entirely and directly take the variables from LandManager since it is always going to exist if everything is in one scene.
has upvoted this post. December 14, 2024 at 2:17 pm #16776 -
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: