Admittedly, I am not very good at coding in C#, but I am learning. I am working on a 2D top down farming game and I am making a few small tests as I get my feet wet to get familiar with C# and Unity at the same time. I wrote a script that progresses the stage of a crop in sprite form every time the space bar is pressed, but I have a few questions.
How do I tie this to a timer that starts once the crop is planted?
How do I set the sprite to change after a certain amount of time has passed, as opposed to pressing the space bar?
I tried this via a switch, but I am not familiar enough with the concept to get it to work properly. I would like to use switch, so I can call back to earlier in the sequence for crops that can have multiple harvests.
Any help is greatly appreciated.
This is what I have at present
using UnityEngine;
using System.Collections;
public class GrowingTest : MonoBehaviour
{
private int GrowStage = 0; //Sets variable called GrowStage
public Sprite stage1; // Drag first crop sprite here
public Sprite stage2; // Drag second crop sprite here
public Sprite stage3; // Drag third crop sprite here
private SpriteRenderer spriteRenderer;
// Use this for initialization
void Start ()
{
spriteRenderer = GetComponent<SpriteRenderer>(); //Calls Sprite Renderer Component from Unity via spriteRenderer alias
}
// Update is called once per frame
void Update ()
{
if (Input.GetKeyDown("space")) //When spacebar is pressed
GrowStage = GrowStage + 1; //Add 1 to GrowStage variable
}
void FixedUpdate()
{
if (GrowStage > 0) //If GrowStage variable is set to 1
{
spriteRenderer.sprite = stage1; //swap to sprite 1
}
if (GrowStage > 1)
{
spriteRenderer.sprite = stage2;
}
if (GrowStage > 2)
{
spriteRenderer.sprite = stage3;
}
}
}
Time.deltaTime is what you want to use to get the elapsed time since the last update, so you will do a += Time.deltaTime on a stored variable.
While we are making small corrections, your FixedUpdate could use a bit of change, by doing IF … ELSE IF … ELSE IF, and changing the conditions.
Right now, it will change the sprite multiple times in the same update, meaning that it uses a bit more resources than it should.
It doesn’t impact things too much for a small project, but it’s good to try and not fall into those small traps.
What you are building is a simple state machine. This is definitely something you want to read up on as a lot of simple game play components require an understanding of this technique.
The code below compiles and is tested within the limits that I care to test for.
The component can be attached to a plant and have the sprites populated through an array in the Inspector. It will also fire events whenever the plant changes state, which is very useful if you want other scripts to know when the plant starts and stops growing or has completely grown.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[RequireComponent(typeof(SpriteRenderer))]
public class GrowthMachine : MonoBehaviour
{
// event to fire when the plant advances to the next growth stage
public delegate void GrownToStageHandler(Object sender, int growthStage, int growthStages);
public event GrownToStageHandler GrownToStage;
// event to fire when the plant has completely grown
public delegate void CompletelyGrownHandler(Object sender, int growthStage, int growthStages);
public event CompletelyGrownHandler CompletelyGrown;
// event to fire when the plant starts to growth
public delegate void StartedGrowingHandler(Object sender, int growthStage, int growthStages);
public event StartedGrowingHandler StartedGrowing;
// event to fire when the plant stops to growth
public delegate void StoppedGrowingHandler(Object sender, int growthStage, int growthStages);
public event StoppedGrowingHandler StoppedGrowing;
// Sprites for each growth stage
[SerializeField]
protected List<Sprite> m_stages;
// how long to wait in seconds between each growth stage
[SerializeField]
[Range(0.01f, 100.0f)]
protected float m_growthRate;
// should I start growing the moment I am planted?
[SerializeField]
protected bool m_growImmediately;
// what stage of growth is this plant at?
private int m_growthStage;
// cached sprite renderer component
private SpriteRenderer m_spriteRenderer;
// indicates whether the plant is growing or not
private bool m_isGrowing;
void Start()
{
m_spriteRenderer = GetComponent<SpriteRenderer>();
// should I start growing the moment I am planted?
if (m_growImmediately)
{
StartGrowing();
}
}
// stops the plant from growing and terminates the coroutine that makes the plant grow
public void StopGrowing()
{
// am I growing? if not, do nothing
if (m_isGrowing == false)
{
return;
}
StopCoroutine(Growing());
m_isGrowing = false;
FireStoppedGrowing();
}
// forces the plant to start growing -- either automatically when it is planted or forcibly
public void StartGrowing()
{
// am I already growing? if so, do nothing
if (m_isGrowing)
{
return;
}
StartCoroutine(Growing());
}
// coroutine that will grow the plant through the various stages to the end
IEnumerator Growing()
{
m_isGrowing = true;
// verify we don't have a negative or zero growth rate
System.Diagnostics.Debug.Assert(m_growthRate > 0.0f);
// verify we have a list of sprites to handle the growth stages
System.Diagnostics.Debug.Assert(m_stages != null);
int stagesToGrow = m_stages.Count;
// verify we have at least one sprite to handle the first growth stage
System.Diagnostics.Debug.Assert(stagesToGrow > 0);
FireStartedGrowing();
ResetGrowth();
for (int i = 1; i < stagesToGrow; i++)
{
yield return new WaitForSeconds(m_growthRate);
AdvanceToNextGrowthStage();
}
m_isGrowing = false;
FireStoppedGrowing();
}
// reset the growth of the plant to the very first stage. Assumes we have a first stage to reset to
public void ResetGrowth()
{
GrowthStage = 0;
}
// advance the plant to the next stage of growth
public void AdvanceToNextGrowthStage()
{
// have we grown to the last stage? if so, do nothing more
if (GrowthStage >= (m_stages.Count - 1))
{
return;
}
// update the sprite to the next growth stage
GrowthStage++;
// let any other scripts paying attention to this plant know about the growth
FireAdvancedToNextStage();
// let any other scripts paying attention to this plant know about reaching the final stage growth
if (GrowthStage == (m_stages.Count - 1))
{
FireCompletelyGrown();
}
}
// reset the script values to sane defaults
void Reset()
{
m_stages = new List<Sprite>();
m_growthRate = 1.0f;
m_growImmediately = true;
}
// inform any other scripts listening to this plant that i've started growing -- either forcibly or because I
// started automatically.
private void FireStartedGrowing()
{
if (StartedGrowing != null)
{
StartedGrowing(this, m_growthStage, m_stages.Count);
}
}
// inform any other scripts listening to this plant that i've stopped growing -- either forcibly or because I
// reached the end of my growth cycle).
private void FireStoppedGrowing()
{
if (StoppedGrowing != null)
{
StoppedGrowing(this, m_growthStage, m_stages.Count);
}
}
// inform any other scripts listening to this plant that i've completely grown up
private void FireCompletelyGrown()
{
if (CompletelyGrown != null)
{
CompletelyGrown(this, (int)(m_growthStage), m_stages.Count);
}
}
// inform any other scripts listening to this plant that i've grown to the next stage
private void FireAdvancedToNextStage()
{
if (GrownToStage != null)
{
GrownToStage(this, (int)(m_growthStage), m_stages.Count);
}
}
// permits the growth stage to be immediately set by other scripts
public int GrowthStage
{
get
{
return m_growthStage;
}
set
{
System.Diagnostics.Debug.Assert(value >= 0);
System.Diagnostics.Debug.Assert(value < m_stages.Count);
m_growthStage = value;
m_spriteRenderer.sprite = m_stages[value];
}
}
// indicates whether the plant is currently growing or not
public bool IsGrowing
{
get
{
return m_isGrowing;
}
}
}
Goodness… I don’t even know what half that stuff means at present, but I certainly appreciate you providing the code. I will copy it and study it until I understand it completely and can configure it myself. I do have a long way to go, but I have a lot of videos from Youtube and various websites (Unity Live Training included) to get a handle on things.