What is a good approach to coding with unity?

Hi.I have 2 simple questions.First:Is this a good approach to write AI(with enums).And Second:Is this a good approach to coding?I mean defining functions below in just one script and not calling them from another script.Do i get any limitations by doing that?

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

public class Behaviours : MonoBehaviour {

    public Transform _currentRoute;
    public string _currentRouteName;
    public float _stoppingDistance;
    public float _patrolSpeed;
    private UnityEngine.AI.NavMeshAgent agent;
    private bool _reversed;
    private int index;

    public enum states {
        patrolling,
        attacking,
        chasing,
    }
    public states CurrentState;
   void Start () {


        CurrentState = states.patrolling;
        agent = gameObject.GetComponent<UnityEngine.AI.NavMeshAgent>();
        agent.stoppingDistance = _stoppingDistance;
        agent.autoBraking = false;
        if (_currentRouteName == "")
            _currentRouteName = GameObject.FindGameObjectWithTag("Route").transform.name;
   }
   void Update ()
{
switch (CurrentState)
        {
            case states.patrolling:
                Patrol(_currentRouteName);
                break;
            case states.attacking:
                Attack();
                break;
            case states.chasing:
               Chase();
                break;
        }
private  void Patrol(){//codes
}
private  void Chase(){//codes
}
private  void Attack(){//codes
}
}

For a state machine in Unity, it’s often better to use a coroutine rather than the update loop. This allows you to write code that executes a process over a number of frames and is very straightforward to read and understand:

void Start() {
StartCoroutine(Patrol() );
}

IEnumerator Patrol() {
while ( true ) {
yield return 0; //wait a frame
MoveTowardsNextPatrolPoint();
if (CanSeePlayer() ) {
yield return StartCoroutine( Chase() );
}
}
}

IEnumerator Chase() {
//blah blah
while (true) {
yield return 0;
if (HasCaughtPlayer() ) {
break;
}
}
}

In this case, he will patrol; when he sees the player, he’ll chase him; after he’s caught him, that coroutine will exit and it’ll return to the Patrol coroutine. Using coroutines makes it a lot easier to follow the flow of the code.

The other popular solution is a fully data-driven one, wherein you can visually edit the state machine flowin an editor window. For this, I recommend picking something up from the asset store.

1 Like

Having done this and consequently ripping it all out I wouldn’t recommend this approach. Trying to wrangle the running coroutines so you don’t end up with multiple running in tandem (or inside each other) is an absolute nightmare.

Also - a set of enums isn’t a very extensible state machine. We use a fairly straightforward implementation.

You have an interface for the state

public interface IState
{
    void Enter();
    void Execute();
    void Exit();
}

which you implement in each of your states. Then your state machine has a method for swapping the current state

public class StateMachine
{
    IState currentState;

    public void ChangeState(IState newState)
    {
        if (currentState != null) currentState.Exit();
        currentState = newState;
        if (currentState != null) currentState.Enter();
    }
}

and a method for ‘ticking’ the current state

public void UpdateCurrentState()
{
    if (currentState != null) currentState.Execute();
}

that gets called in the state machine’s owner’s Update method.

In our implementation we pass the owner to each state so everything is self-contained in the state itself.

You use Enter to initialize the state and Exit to clean it up. This also guarantees that only one state is ever executing at a time.

1 Like

Thank you for both replies.Coroutine way seems a bit easier but interface looks more interesting.I’m going to try both.What about my general scripting?Is it any good?Or should i write classes and call functions with instances of those classes?

Not sure what you mean… you DID write a class and you ARE calling functions on an instance of that class. If you just mean should you break it all up into multiple smaller classes, then that really depends on how big the code gets and whether you’d actually use the smaller classes individually.