In this script, a worker leaves his home, looks for a tree to cut, cuts the tree and returns home. It all happens very fast at the moment, he sprints from home, tree, home, tree. and so on. I would like him to rest for a while before he goes out looking for new work. How would I get around this? I’ve read about coroutines, timers and several different options, but I think that many of them seem a bit overkill. Hope someone here has a good solution.
Right now the script looks like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WoodCutterDetector : MonoBehaviour
{
public GameObject home;
private GameObject tree;
bool working = false;
bool carryingTree = false;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (working)
{
if(!carryingTree) {
MoveToTree(tree);
} else {
MoveHome ();
}
} else {
GetTreeInRange();
}
}
void MoveHome() {
Vector3 homePosition = home.transform.position;
Vector3 workerPosition = transform.position;
transform.position = Vector3.Lerp(workerPosition, homePosition, 0.1f);
if (Vector3.Distance(homePosition, workerPosition) <= 0.1f)
{
working = false;
carryingTree = false;
}
}
void MoveToTree(GameObject tree)
{
Vector3 treePosition = tree.transform.position;
Vector3 workerPosition = transform.position;
transform.position = Vector3.Lerp(workerPosition, treePosition, 0.1f);
if (Vector3.Distance(treePosition, workerPosition) <= 0.1f)
{
Destroy(tree);
tree = null;
carryingTree = true;
}
}
void GetTreeInRange()
{
GameObject[] trees = GameObject.FindGameObjectsWithTag("Tree");
foreach (GameObject t in trees)
{
float distance = Vector3.Distance(t.transform.position, transform.position);
if (distance <= 5f)
{
tree = t;
working = true;
return;
}
}
}
}
Coroutines are what you want to use for modular behaviour like this. Here’s a simple example with your script. Notice there isn’t even a need for the Update() method. Instead you have states that transition to where they need to go and process their behavior.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WoodCutterDetector : MonoBehaviour
{
public GameObject home;
bool working = false;
bool carryingTree = false;
float characterSpeed = 1f;
void Start()
{
StartCoroutine(BeginWorkerFSM());
}
IEnumerator BeginWorkerFSM()
{
while(this.enabled) //Keep running while this script is active
{
yield return StartCoroutine(StartWorking());
//if we return, then we've finished working and could execute something else, like
//yield return StartCoroutine(GoToBed());
yield return null;
}
}
IEnumerator StartWorking()
{
while(working)
{
yield return StartCoroutine(MoveToTree(GetTreeInRange())); //Find a tree and walk to it
yield return StartCoroutine(MoveHome()); //Take the tree home.
//Do some checks here, should we stop working and do something else now? if so, set working = false
//like: if "all out of wood to collecting", working = false;
}
}
IEnumerator MoveHome() {
yield return StartCoroutine(MoveTo(home.transform));
carryingTree = false;
}
IEnumerator MoveToTree(GameObject tree)
{
if(tree != null)
{
yield return StartCoroutine(MoveTo(tree.transform)); //Return to this function once our MoveTo() routine finishes
StartCoroutine(ChopWood(tree)); //Start chopping our tree
} else {
working = false; //out of wood, stop working
}
}
//Routine to reuse for moving from place to place
IEnumerator MoveTo(Transform target)
{
while(transform.position != target.position)
{
transform.position = Vector3.MoveTowards(transform.position, target.position, Time.deltaTime * characterSpeed); //Move to target by our speed each frame
yield return null; //Wait for next frame
}
}
IEnumerator ChopWood(GameObject tree)
{
//Start a tree cutting animation here and do a "while chopping animation plying { yield return null;}"
//Or just a yield return new WaitForSeconds(chopTime);
//Then this stuff
Destroy(tree);
carryingTree = true;
yield return null;
}
GameObject GetTreeInRange()
{
GameObject[] trees = GameObject.FindGameObjectsWithTag("Tree"); //Not something you should be doing frequently...
foreach (GameObject t in trees)
{
if (Vector3.Distance(t.transform.position, transform.position) <= 5f)
{
return t;
}
}
return null;
}
}