Forum begins after the advertisement:

 


[Part 11] The tree wilted after scene transitions

Home Forums Video Game Tutorial Series Creating a Farming RPG in Unity [Part 11] The tree wilted after scene transitions

Viewing 5 posts - 1 through 5 (of 5 total)
  • Author
    Posts
  • #17626
    20_Nguyễn Hoàng Long
    Level 1
    Participant
    Helpful?
    Up
    0
    ::
    View post on imgur.com

    After I finished part 11 something happened. I planted some seeds and moved to another scene and then came back. Some seeds disappeared, some turned into withered plants.

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Land : MonoBehaviour, ITimeTracker
    {
        public int id;
        public enum LandStatus
        {
            Soil, Farmland, Watered
        }
    
        public LandStatus landStatus;
    
        public Material soilMat, farmlandMat, wateredMat;
        new Renderer renderer;
    
        //The selection gameobject to enable when the player is selecting the land
        public GameObject select;
    
        //Cache the time the land was watered 
        GameTimestamp timeWatered;
    
        [Header("Crops")]
        //The crop prefab to instantiate
        public GameObject cropPrefab;
    
        //The crop currently planted on the land
        CropBehaviour cropPlanted = null;
    
        // Start is called before the first frame update
        void Start()
        {
            //Get the renderer component
            renderer = GetComponent<Renderer>();
    
            //Set the land to soil by default
            SwitchLandStatus(LandStatus.Soil);
    
            //Deselect the land by default
            Select(false);
    
            //Add this to TimeManager's Listener list
            TimeManager.Instance.RegisterTracker(this);
        }
    
        public void LoadLandData(LandStatus statusToSwitch, GameTimestamp lastWatered)
        {
            //Set land status accordingly
            landStatus = statusToSwitch;
            timeWatered = lastWatered;
    
            Material materialToSwitch = soilMat;
    
            //Decide what material to switch to
            switch (statusToSwitch)
            {
                case LandStatus.Soil:
                    //Switch to the soil material
                    materialToSwitch = soilMat;
                    break;
                case LandStatus.Farmland:
                    //Switch to farmland material 
                    materialToSwitch = farmlandMat;
                    break;
    
                case LandStatus.Watered:
                    //Switch to watered material
                    materialToSwitch = wateredMat;
                    break;
    
            }
    
            //Get the renderer to apply the changes
            renderer.material = materialToSwitch;
    
        }
    
        public void SwitchLandStatus(LandStatus statusToSwitch)
        {
            //Set land status accordingly
            landStatus = statusToSwitch;
    
            Material materialToSwitch = soilMat;
    
            //Decide what material to switch to
            switch (statusToSwitch)
            {
                case LandStatus.Soil:
                    //Switch to the soil material
                    materialToSwitch = soilMat;
                    break;
                case LandStatus.Farmland:
                    //Switch to farmland material 
                    materialToSwitch = farmlandMat;
                    break;
    
                case LandStatus.Watered:
                    //Switch to watered material
                    materialToSwitch = wateredMat;
    
                    //Cache the time it was watered
                    timeWatered = TimeManager.Instance.GetGameTimestamp();
                    break;
    
            }
    
            //Get the renderer to apply the changes
            renderer.material = materialToSwitch;
    
            LandManager.Instance.OnLandStateChange(id, landStatus, timeWatered);
        }
    
        public void Select(bool toggle)
        {
            select.SetActive(toggle);
        }
    
        //When the player presses the interact button while selecting this land
        public void Interact()
        {
            //Check the player's tool slot
            ItemData toolSlot = InventoryManager.Instance.GetEquippedSlotItem(InventorySlot.InventoryType.Tool);
    
            //If there's nothing equipped, return
            if (!InventoryManager.Instance.SlotEquipped(InventorySlot.InventoryType.Tool))
            {
                return;
            }
    
            //Try casting the itemdata in the toolslot as EquipmentData
            EquipmentData equipmentTool = toolSlot as EquipmentData;
    
            //Check if it is of type EquipmentData 
            if (equipmentTool != null)
            {
                //Get the tool type
                EquipmentData.ToolType toolType = equipmentTool.toolType;
    
                switch (toolType)
                {
                    case EquipmentData.ToolType.Hoe:
                        SwitchLandStatus(LandStatus.Farmland);
                        break;
                    case EquipmentData.ToolType.WateringCan:
                        //The land must be tilled first
                        if (landStatus != LandStatus.Soil)
                        {
                            SwitchLandStatus(LandStatus.Watered);
                        }
    
                        break;
    
                    case EquipmentData.ToolType.Shovel:
    
                        //Remove the crop from the land
                        if (cropPlanted != null)
                        {
                            cropPlanted.RemoveCrop();
                        }
                        break;
                }
    
                //We don't need to check for seeds if we have already confirmed the tool to be an equipment
                return;
            }
    
            //Try casting the itemdata in the toolslot as SeedData
            SeedData seedTool = toolSlot as SeedData;
    
            ///Conditions for the player to be able to plant a seed
            ///1: He is holding a tool of type SeedData
            ///2: The Land State must be either watered or farmland
            ///3. There isn't already a crop that has been planted
            if (seedTool != null && landStatus != LandStatus.Soil && cropPlanted == null)
            {
                SpawnCrop();
                //Plant it with the seed's information
                cropPlanted.Plant(id, seedTool);
    
                //Consume the item
                InventoryManager.Instance.ConsumeItem(InventoryManager.Instance.GetEquippedSlot(InventorySlot.InventoryType.Tool));
    
            }
        }
    
        public CropBehaviour SpawnCrop()
        {
            //Instantiate the crop object parented to the land
            GameObject cropObject = Instantiate(cropPrefab, transform);
            //Move the crop object to the top of the land gameobject
            cropObject.transform.position = new Vector3(transform.position.x, 0.2f, transform.position.z);
    
            //Access the CropBehaviour of the crop we're going to plant
            cropPlanted = cropObject.GetComponent<CropBehaviour>();
            return cropPlanted;
        }
    
        public void ClockUpdate(GameTimestamp timestamp)
        {
            //Checked if 24 hours has passed since last watered
            if (landStatus == LandStatus.Watered)
            {
                //Hours since the land was watered
                int hoursElapsed = GameTimestamp.CompareTimestamps(timeWatered, timestamp);
                Debug.Log(hoursElapsed + " hours since this was watered");
    
                //Grow the planted crop, if any
                if (cropPlanted != null)
                {
                    cropPlanted.Grow();
                }
    
                if (hoursElapsed > 24)
                {
                    //Dry up (Switch back to farmland)
                    SwitchLandStatus(LandStatus.Farmland);
                }
            }
    
            //Handle the wilting of the plant when the land is not watered
            if (landStatus != LandStatus.Watered && cropPlanted != null)
            {
                //If the crop has already germinated, start the withering
                if (cropPlanted.cropState != CropBehaviour.CropState.Seed)
                {
                    cropPlanted.Wither();
                }
            }
        }
    }
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class LandManager : MonoBehaviour
    {
        public static LandManager Instance { get; private set; }
        public static Tuple<List<LandSaveState>, List<CropSaveState>> farmData = null;
    
        List<Land> landPlots = new List<Land>();
        List<LandSaveState> landData = new List<LandSaveState>();
        List<CropSaveState> cropData = new List<CropSaveState>();
    
    
        private void Awake()
        {
            //If there is more than one instance, destroy the extra
            if (Instance != null && Instance != this)
            {
                Destroy(this);
            }
            else
            {
                //Set the static instance to this instance
                Instance = this;
            }
        }
    
    
        void OnEnable()
        {
            RegisterLandPlots();
            StartCoroutine(LoadFarmData());
        }
        IEnumerator LoadFarmData()
        {
            yield return new WaitForEndOfFrame();
            //Load farm data if any
            if (farmData != null)
            {
                //Load in any saved data 
                ImportLandData(farmData.Item1);
                ImportCropData(farmData.Item2);
            }
    
        }
        private void OnDestroy()
        {
            //Save the Instance variables over to the static variable
            farmData = new Tuple<List<LandSaveState>, List<CropSaveState>>(landData, cropData);
        }
    
        //Get all the Land Objects in the scene and cache it
        void RegisterLandPlots()
        {
            foreach (Transform landTransform in transform)
            {
                Land land = landTransform.GetComponent<Land>();
                landPlots.Add(land);
    
                //Create a corresponding LandSaveState
                landData.Add(new LandSaveState());
    
                //Assign it an id based on its index
                land.id = landPlots.Count - 1;
            }
        }
        //Registers the crop onto the Instance
        public void RegisterCrop(int landID, SeedData seedToGrow, CropBehaviour.CropState cropState, int growth, int health)
        {
            cropData.Add(new CropSaveState(landID, seedToGrow.name, cropState, growth, health));
        }
        public void DeregisterCrop(int landID)
        {
            //Find its index in the list from the landID and remove it
            cropData.RemoveAll(x => x.landID == landID);
        }
        //Update the corresponding Land Data on ever change to the Land's state
        public void OnLandStateChange(int id, Land.LandStatus landStatus, GameTimestamp lastWatered)
        {
            landData[id] = new LandSaveState(landStatus, lastWatered);
        }
        //Update the corresponding Crop Data on ever change to the Land's state
        public void OnCropStateChange(int landID, CropBehaviour.CropState cropState, int growth, int health)
        {
            //Find its index in the list from the landID
            int cropIndex = cropData.FindIndex(x => x.landID == landID);
    
            string seedToGrow = cropData[cropIndex].seedToGrow;
            cropData[cropIndex] = new CropSaveState(landID, seedToGrow, cropState, growth, health);
        }
        //Load over the static farmData onto the Instance's landData
        public void ImportLandData(List<LandSaveState> landDatasetToLoad)
        {
            for (int i = 0; i < landDatasetToLoad.Count; i++)
            {
                //Get the individual land save state
                LandSaveState landDataToLoad = landDatasetToLoad[i];
                //Load it up onto the Land instance
                landPlots[i].LoadLandData(landDataToLoad.landStatus, landDataToLoad.lastWatered);
    
            }
    
            landData = landDatasetToLoad;
        }
        //Load over the static farmData onto the Instance's cropData
        public void ImportCropData(List<CropSaveState> cropDatasetToLoad)
        {
            cropData = cropDatasetToLoad;
            foreach (CropSaveState cropSave in cropDatasetToLoad)
            {
                //Access the land
                Land landToPlant = landPlots[cropSave.landID];
                //Spawn the crop
                CropBehaviour cropToPlant = landToPlant.SpawnCrop();
                Debug.Log(cropToPlant.gameObject);
                //Load in the data
                SeedData seedToGrow = (SeedData)InventoryManager.Instance.itemIndex.GetItemFromString(cropSave.seedToGrow);
                cropToPlant.LoadCrop(cropSave.landID, seedToGrow, cropSave.cropState, cropSave.growth, cropSave.health);
            }
        }
        // Update is called once per frame
        void Update()
        {
    
        }
    }

    ‘using System.Collections; using System.Collections.Generic; using UnityEngine;

    public class CropBehaviour : MonoBehaviour { //The ID of the land the crop belongs to int landID;

    //Information on what the crop will grow into 
    SeedData seedToGrow;
    
    [Header("Stages of Life")]
    public GameObject seed;
    public GameObject wilted;
    private GameObject seedling;
    private GameObject harvestable;
    
    
    //The growth points of the crop
    int growth;
    //How many growth points it takes before it becomes harvestable
    int maxGrowth;
    
    //The crop can stay alive for 48 hours without water before it dies
    int maxHealth = GameTimestamp.HoursToMinutes(48);
    
    int health;
    
    public enum CropState
    {
        Seed, Seedling, Harvestable, Wilted
    }
    //The current stage in the crop's growth
    public CropState cropState;
    
    //Initialisation for the crop GameObject
    //Called when the player plants a seed
    public void Plant(int landID, SeedData seedToGrow)
    {
        LoadCrop(landID, seedToGrow, CropState.Seed, 0, 0);
        LandManager.Instance.RegisterCrop(landID, seedToGrow, cropState, growth, health);
    
    }
    
    public void LoadCrop(int landID, SeedData seedToGrow, CropState cropState, int growth, int health)
    {
        this.landID = landID;
        //Save the seed information
        this.seedToGrow = seedToGrow;
    
        //Instantiate the seedling and harvestable GameObjects
        seedling = Instantiate(seedToGrow.seedling, transform);
    
        //Access the crop item data
        ItemData cropToYield = seedToGrow.cropToYield;
    
        //Instantiate the harvestable crop
        harvestable = Instantiate(cropToYield.gameModel, transform);
    
        //Convert Days To Grow into hours
        int hoursToGrow = GameTimestamp.DaysToHours(seedToGrow.daysToGrow);
        //Convert it to minutes
        maxGrowth = GameTimestamp.HoursToMinutes(hoursToGrow);
    
        //Set the growth and health accordingly
        this.growth = growth;
        this.health = health;
    
        //Check if it is regrowable
        if (seedToGrow.regrowable)
        {
            //Get the RegrowableHarvestBehaviour from the GameObject
            RegrowableHarvestBehaviour regrowableHarvest = harvestable.GetComponent<RegrowableHarvestBehaviour>();
    
            //Initialise the harvestable 
            regrowableHarvest.SetParent(this);
        }
    
        //Set the initial state to Seed
        SwitchState(cropState);
    
    }
    
    //The crop will grow when watered
    public void Grow()
    {
        //Increase the growth point by 1
        growth++;
    
        //Restore the health of the plant when it is watered
        if (health < maxHealth)
        {
            health++;
        }
    
        //The seed will sprout into a seedling when the growth is at 50%
        if (growth >= maxGrowth / 2 && cropState == CropState.Seed)
        {
            SwitchState(CropState.Seedling);
        }
    
        //Grow from seedling to harvestable
        if (growth >= maxGrowth && cropState == CropState.Seedling)
        {
            SwitchState(CropState.Harvestable);
        }
    
        //Inform LandManager on the changes
        LandManager.Instance.OnCropStateChange(landID, cropState, growth, health);
    }
    
    //The crop will progressively wither when the soil is dry 
    public void Wither()
    {
        health--;
        //If the health is below 0 and the crop has germinated, kill it
        if (health <= 0 && cropState != CropState.Seed)
        {
            SwitchState(CropState.Wilted);
        }
    
        //Inform LandManager on the changes
        LandManager.Instance.OnCropStateChange(landID, cropState, growth, health);
    }
    
    //Function to handle the state changes 
    void SwitchState(CropState stateToSwitch)
    {
        //Reset everything and set all GameObjects to inactive
        seed.SetActive(false);
        seedling.SetActive(false);
        harvestable.SetActive(false);
        wilted.SetActive(false);
    
        switch (stateToSwitch)
        {
            case CropState.Seed:
                //Enable the Seed GameObject
                seed.SetActive(true);
                break;
            case CropState.Seedling:
                //Enable the Seedling GameObject
                seedling.SetActive(true);
    
                //Give the seed health 
                health = maxHealth;
    
                break;
            case CropState.Harvestable:
                //Enable the Harvestable GameObject
                harvestable.SetActive(true);
    
                //If the seed is not regrowable, detach the harvestable from this crop gameobject and destroy it. 
                if (!seedToGrow.regrowable)
                {
                    //Unparent it to the crop
                    harvestable.transform.parent = null;
                    RemoveCrop();
                }
    
    
                break;
            case CropState.Wilted:
                //Enable the wilted GameObject
                wilted.SetActive(true);
                break;
        }
    
        //Set the current crop state to the state we're switching to
        cropState = stateToSwitch;
    }
    
    //Destroys and Deregisters the Crop
    public void RemoveCrop()
    {
        LandManager.Instance.DeregisterCrop(landID);
        Destroy(gameObject);
    }
    
    //Called when the player harvests a regrowable crop. Resets the state to seedling 
    public void Regrow()
    {
        //Reset the growth 
        //Get the regrowth time in hours
        int hoursToRegrow = GameTimestamp.DaysToHours(seedToGrow.daysToRegrow);
        growth = maxGrowth - GameTimestamp.HoursToMinutes(hoursToRegrow);
    
        //Switch the state back to seedling
        SwitchState(CropState.Seedling);
    }

    }’

    #17627
    Tarha Apustaja
    Level 4
    AI Assistant
    (BETA)
    Helpful?
    Up
    0
    ::

    Based on the reference information, this is likely happening because of the scene transition and how the LandManager handles saving and loading crop data.

    The crops are disappearing or withering because the farmData static variable in LandManager is being used to persist crop state between scene transitions. When you move to another scene and come back, the crops are being loaded from this saved state, which might have incomplete or partially degraded data.

    To troubleshoot, I recommend checking:

    1. Are you properly saving the farmData before scene transition?
    2. Is the farmData being reset accidentally during scene load?
    3. Are the crops’ health and growth states being correctly preserved?

    Would you like me to help you review the scene transition and data saving process to ensure crop data is correctly maintained?

    #17628
    20_Nguyễn Hoàng Long
    Level 1
    Participant
    Helpful?
    Up
    0
    ::

    To be precise, only the first seed planted became a withered plant, all the remaining seeds disappeared.

    #17629
    Tarha Apustaja
    Level 4
    AI Assistant
    (BETA)
    Helpful?
    Up
    0
    ::

    Based on the reference information and the updated specifics, this suggests a potential issue with how crops are being saved and loaded during scene transitions.

    The fact that one seed became a withered plant while others disappeared entirely points to an inconsistency in the crop data saving mechanism. This could be related to how the LandManager.ImportCropData() method handles crop restoration.

    Could you confirm:

    1. Are all crop prefabs set up identically in your scene?
    2. Did you check if the farmData static variable contains all the crop save states before and after scene transition?
    3. Are there any error messages in the console during scene loading?

    To help diagnose the issue more precisely, could you provide more details about how you’re managing scene transitions and what specific steps you’re taking when moving between scenes?

    #17703
    Jonathan Teo
    Level 18
    Moderator
    Helpful?
    Up
    0
    ::

    Try to debug as Tarha has directed, and if not you can refer to this thread which another user encountered a similar problem

Viewing 5 posts - 1 through 5 (of 5 total)
  • You must be logged in to reply to this topic.

Go to Login Page →


Advertisement below: