How to make crops mature over time like in Stardew Valley?

What’s the easiest way to make crops that mature after a set amount of time in Unity / C#? I want to plant a seed and then have it transform into a tiny plant, then a full-grown plant which can be harvested.

I’ve tried to make one prefab instantiate another and then destroy itself, but that doesn’t seem to be working. Plus I’m having trouble assigning position and rotation that way.

I’m guessing there is probably an easier way to just transform/swap/replace one prefab for another, in the same location, once a set amount of time has passed??

I’ve looked through tons of Youtube tutorials with the keywords Unity + stardew, farming, or anything similar. All I’ve found is devlogs showing off crop growth but no tutorials or code displayed. (I suspect some of them are just using extremely slow animations – but then I’m not sure how the game would know when a plant is ready to harvest or not.)

what problem are you having with the prefab creating another prefab then destroying itself?

Me personally, I’d probably just have a script control which sprite is displayed for the crop, but if you’re doing complex stuff like animation that may not be a great way to go.

Easiest way is to just update the sprite and using a variable that indicates growth stage.

First I create a script to handle drawing the plants.

public class PlantAnimator
{
    //lets declare memory for three sprites
   Sprite[] tomato = new Sprite[3];
   //called when project loads or when first gameplay scene loads
   public void LoadGraphics()
   {
      //lets load graphics for a three level tomato
      for(int i = 0; i < 3; i++)
      {
         //put graphics into your project's Assets\Resources folder
         //in my example I put folders \Graphics\Plants\Tomato as well
         //"Tomato0" "Tomato1" "Tomato2"
         Resources.Load<Sprite>("Graphics/Plants/Tomato" + i);
      }
   }
   //a function to call when you want to update your sprite
   public void UpdateTomatoGraphic(SpriteRenderer sr, int plantStage)
   {
      sr.sprite = tomato[plantStage];
   }
}

Then whenever I want to update a tomato plant I would call our UpdateTomatoGraphic function.

plantAnimator.UpdateTomatoGraphic(currentTomatoSpriteRenderer, currentTomatoStage);

You can use flip-book (animation sheets).

Here is a video I used to learn about using real world time for events. This one is for how much time has passed since last playing the game but the same logic can be applied to your crops. After X seconds, whether the apps is running or closed, the sprite can update. Using adehm’s logic above is probably best to update the sprite at each stage so you arent instantiating when all you need to do is change the sprite in the sprite renderer component.

A simple way of counting time would be to use a float for a timer. Let’s imagine each plant has its own script for simplicity but I prefer arrays to hold all of the plants.

If counting time.

float timer = 0;
float duration = 1; //1 second
void Update()
{
   timer+=Time.deltaTime;
   if(timer>=duration) //1 second has passed
   {
      timer-=duration;
   }
}

But as in your game you would be counting days since planted right? So would be even simplier because every day just talk to your plants and add the day.

int daysSincePlanted = 0;
public void UpdateDay()
{
    daysSincePlanted++;
}

I’m not sure how to get the second prefab to know where to instantiate. The problem is that the first prefab doesn’t exist when the scene starts, until it’s placed by the player. So I’m not sure how to refer to an object position/rotation that isn’t in the scene yet.

Here is how the initial seed gets planted, which works fine:

public Transform placePoint;
//placePoint is an empty GameObject on the player that indicates where a seed should be planted
public GameObject seedPrefab;

void Update()
    {
        if (Input.GetButtonDown("Fire1"))
        {
            Plant();
        }
        }

        void Plant (){
            //planting logic
            Instantiate(seedPrefab, placePoint.position, placePoint.rotation);
        }

The problem is turning the seed into a plant in another script:

public GameObject seed;
public GameObject seedPrefab;
 public GameObject plantPrefab;

    void Update()
    {
        Invoke("Grow", 2);
    }

    void Grow()
    {Instantiate(plantPrefab,seedPrefab.position, seedPrefab.rotation)
     Destroy(gameObject);
    }

I get an error on the .position and .rotation saying “GameObject does not contain a definition for “position” and no accessible extention method “position” accepting a first argument of type “GameObject” could be found (are you missing a using directive or an assembly reference?)”

If I change “public GameObject seedPrefab” to “public Transform seedPrefab” the error goes away, but the plant isn’t spawning where the seed was.

I think I might’ve had an if statement in the update method yesterday, but I forget what it was now. Now I realize it’s just invoking a random plant at a random position in the scene without regard for where the seed is, or if there is one.

I might need an if statement for the Invoke command, which then starts the Grow method if a seed exists? But then I worry how I’m going to differentiate between different seeds if there are multiple planted on the screen at a time.

Maybe I need to figure out how to use a sprite renderer command and not instantiating or using prefabs at all. Sorry I’m so new at this that I dont even know where to start.

To get a game object’s position, you have to first refer to the transform element.

So transform.position, and transform.rotation. So just copy that along to the new prefab.

You tend to use transform quite a bit as it is a link between subordinate scripts and the main game object they are attached too.

I think it will be much easier to work with. The main reason is think about it this way, The Seed and Flower are technically the same thing, they just look different and have small behavior differences. So lets say you have 4 phases: Seed>Sprout>Baby Plant>Fully Grown. All you need are 4 sprites and when each phase occurs, you change the sprite (see link below). Now, if you want to change behavior, you can add and remove scripts from that gameobject at any phase as well.

Another benefit is this. If you have 4 phases and continue with your Prefab instantiation, then you will still need 4 sprites AND 4 separate gameobjects to keep track of. If you just mess with the sprites, you have 4 sprites and 1 gameobject prefab. You go from 8 objects to keep track of to 5. That can get really messy if you have 10 plants or more. I hope this makes sense.

https://gamedevbeginner.com/how-to-change-a-sprite-from-a-script-in-unity-with-examples/