AI scripting doubts.

Hello,

I’m building a shoot’em up where a script called “Scene_Director” instantiates the waves of enemies at regular times.
Now, each single enemy of each single wave has to follow a path which will be different from another enemy of the same wave, so, I built a script called “PatternScript” which basically holds a bunch of methods which (depending on an argument I’m passing from the Scene_Director) will move the enemy through a path.
In code:

Scene_Director:

public class TestScene_DirectorScript : MonoBehaviour {

    private float time;

    private bool[] flags = new bool [10];    // tool for controlling waves

    public Transform enemy1_prefab;

    // Use this for initialization
    void Start () {
        time = 0;
        for (int i = 0; i < 10; i++)
            flags [i] = false;
    }
  
    // Update is called once per frame
    void Update () {
        time += Time.deltaTime;
        if (time > 1.0f && flags[0] == false)
        {  
            flags [0] = true;
            WaveOne ();
        }
    }

    void WaveOne()
    {
        var spawn = Instantiate (enemy1_prefab) as Transform;
        spawn.position = new Vector3 (-2.0f, 4.0f, 5.0f);
        MovePatternScript mvs = spawn.GetComponent<PatternScript> ();
        mvs.SetTargetPos (new Vector3(-2.0f, 0.0f, 5.0f));
        mvs.SetPattern (1);
        spawn = Instantiate (enemy1_prefab) as Transform;
        spawn.position = new Vector3 (2.0f, 4.0f, 5.0f);
        mvs = spawn.GetComponent<PatternScript> ();
        mvs.SetTargetPos (new Vector3(-2.0f, 0.0f, 5.0f));
        mvs.SetPattern (1);
    }
}

PatternScript:

public class PatternScript : MonoBehaviour {

    public int pattern = 0;

    private bool initializated;

    private Vector3 v;
    private Vector3 movement;
    public Vector3 targetPos;

    // Use this for initialization
    void Start () {
        targetPos = new Vector3 (0.0f, 0.0f, 5.0f);
    }
  
    // Update is called once per frame
    void Update () {
      
        switch (pattern)
        {
            case 1:
                PatternOne ();
                break;
            case 2:
                break;
            case 3:
                break;
            case 4:
                break;
        }

    }

    public void SetPattern(int n)
    {
        pattern = n;
    }

    public void SetTargetPos(Vector3 x)
    {
        targetPos = x;
    }
      
    void PatternOne()
    {
// Example, it might also be a Bezier Curve
        transform.position = Vector3.MoveTowards (transform.position, targetPos, 0.05f);
    }
}

You see how TEDIOUS it is? The Scene_Director has, for each enemy, grab the Pattern_Script, point the target position and which pattern to use. Also, you need to write at least 5 lines of code for each enemy, while a wave usually holds 10+ enemies. Plus, that is the easiest pattern, try to figure out how to describe a Bezier Curve.

In C++ it would be extremely easy by having a custom constructor:

Enemy::Enemy(glm::vec3 startPos, glm::vec3 endPos, int pattern)
{
// spawn the enemy at startPos, bring it to endPos using pattern
}

So you can call:

Enemy* e = new Enemy (glm::vec3, glm::vec3, int)

Finally, the question is: what solution do you suggest to shorten and optimize the code for Scene_Director/Pattern_Script by also keeping an eye to abstraction?

Sorry for the long post, thanks in advance.

You can use constructors in C# too.

You can actually go one better and expose it all to the inspector. This makes configuration and iteration really, really easy.

Could you please post an example of an instatiation of a prefab through a C# constructor? As you can see I’m pretty newbie in C#, my territory is more C++. :slight_smile:

Exposing everything to the inspector is not a problem, but this implies having 100+ disabled gameobjects on my scene. Isn’t it? Or am I missing something important?

All good. You can’t build a constructor for a MonoBehaviour, as Unity runs its own special constructor. But you can build a constructor on a vanilla class and pass that through to your MonoBehaviour.

Yes. You can expose vanilla classes to the inspector in a collection on a single GameObject or ScriptableObject.

This is generally how I code wave like behavior.

public class WaveGenerator : MonoBehaviour {
    [SerialiseField]
    List<Wave> waves;

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

    IEnumerator GenerateWaves (){
        foreach (Wave wave in Waves){
            yield return new WaitForSeconds (wave.delayTime);
            // Instantiate the wave
        }
        yield return null;
    }
}

[System.Serialisable]
public class Wave {
    public GameObject enemyPrefab;
    public int noOfEnemies;
    public float delayTime;
}

You can follow the same pattern to set up the various patterns. Just expose a List and in each Pattern expose a List.

Does that make sense?

Yes! This is great! I’m gonna give it a try now.

Thanks a lot for your help! Later on I’ll post here the result and/or any problem if you don’t mind. :stuck_out_tongue:

Thanks again!