-1

update...

First Class

using UnityEngine;
using System.Collections;

[System.Serializable]
public class Wave
{
    public GameObject enemyPrefab;
    public float spawnInterval = 2;
    public int maxEnemies = 20;
}

public class SpawnEnemy : MonoBehaviour
{

    public GameObject[] waypoints;
    public GameObject testEnemyPrefab;

    public Wave[] waves;
    public int timeBetweenWaves = 5;

    private GameManagerBehavior gameManager;

    private float lastSpawnTime;
    private int enemiesSpawned = 0;

    // Use this for initialization
    void Start()
    {
        lastSpawnTime = Time.time;
        gameManager =
            GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
    }

    // Update is called once per frame
    void Update()
    {
        // 1 Get the index of the current wave, and check if it’s the last one.
        int currentWave = gameManager.Wave;
        if (currentWave < waves.Length)
        {
            // 2 If so, calculate how much time passed since the last enemy spawn and whether it’s time to spawn an enemy. Here you consider two cases.
            // If it’s the first enemy in the wave, you check whether timeInterval is bigger than timeBetweenWaves.
            // Otherwise, you check whether timeInterval is bigger than this wave’s spawnInterval. In either case, you make sure you haven’t spawned all the enemies for this wave.
            float timeInterval = Time.time - lastSpawnTime;
            float spawnInterval = waves[currentWave].spawnInterval;
            if (((enemiesSpawned == 0 && timeInterval > timeBetweenWaves) ||
                 timeInterval > spawnInterval) &&
                enemiesSpawned < waves[currentWave].maxEnemies)
            {
                // 3 If necessary, spawn an enemy by instantiating a copy of enemyPrefab. You also increase the enemiesSpawned count.
                lastSpawnTime = Time.time;
                GameObject newEnemy = (GameObject)
                    Instantiate(waves[currentWave].enemyPrefab);
                newEnemy.GetComponent<MoveEnemy>().waypoints = waypoints;
                newEnemy.GetComponent<MoveEnemy>().JiggleWaypoints();
                enemiesSpawned++;
            }
            // 4 You check the number of enemies on screen. If there are none and it was the last enemy in the wave you spawn the next wave.
            // You also give the player 10 percent of all gold left at the end of the wave.
            if (enemiesSpawned == waves[currentWave].maxEnemies &&
                GameObject.FindGameObjectWithTag("Enemy") == null)
            {
                gameManager.Wave++;
                gameManager.Gold = Mathf.RoundToInt(gameManager.Gold * 1.1f);
                enemiesSpawned = 0;
                lastSpawnTime = Time.time;
            }
            // 5 Upon beating the last wave this runs the game won animation.
        }
        else {
            gameManager.gameOver = true;
            GameObject gameOverText = GameObject.FindGameObjectWithTag("GameWon");
            gameOverText.GetComponent<Animator>().SetBool("gameOver", true);
        }
    }
}

Second Class

using UnityEngine;
using System.Collections;

public class MoveEnemy : MonoBehaviour
{

    [System.NonSerialized]
    public GameObject[] waypoints;
    private int currentWaypoint = 0;
    private float lastWaypointSwitchTime;
    public float speed = 1.0f;

    // Use this for initialization
    void Start()
    {
        lastWaypointSwitchTime = Time.time;
    }

    // Update is called once per frame
    void Update()
    {
        // 1 
        Vector3 startPosition = waypoints[currentWaypoint].transform.position;
        Vector3 endPosition = waypoints[currentWaypoint + 1].transform.position;
        // 2 
        float pathLength = Vector3.Distance(startPosition, endPosition);
        float totalTimeForPath = pathLength / speed;
        float currentTimeOnPath = Time.time - lastWaypointSwitchTime;
        gameObject.transform.position = Vector3.Lerp(startPosition, endPosition, currentTimeOnPath / totalTimeForPath);
        // 3 
        if (gameObject.transform.position.Equals(endPosition))
        {
            if (currentWaypoint < waypoints.Length - 2)
            {
                // 3.a 
                currentWaypoint++;
                lastWaypointSwitchTime = Time.time;
                RotateIntoMoveDirection();
            }
            else {
                // 3.b 
                Destroy(gameObject);

                AudioSource audioSource = gameObject.GetComponent<AudioSource>();
                AudioSource.PlayClipAtPoint(audioSource.clip, transform.position);
                //<< deduct health
                GameManagerBehavior gameManager =
    GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
                gameManager.Health -= 1;
                //>>
            }
        }
    }

    public void JiggleWaypoints()
    {
        for (int i = 1; i < waypoints.Length; i++)
        {
            waypoints[i].transform.position = new Vector3(waypoints[i].transform.position.x + Random.Range(-3, 3), waypoints[i].transform.position.y + Random.Range(-3, 3), 0);
        }
    }

    private void RotateIntoMoveDirection()
    {
        //1 It calculates the bug’s current movement direction by subtracting the current waypoint’s position from that of the next waypoint.
        Vector3 newStartPosition = waypoints[currentWaypoint].transform.position;
        Vector3 newEndPosition = waypoints[currentWaypoint + 1].transform.position;
        Vector3 newDirection = (newEndPosition - newStartPosition);
        //2 It uses Mathf.Atan2 to determine the angle toward which newDirection points, in radians, assuming zero points to the right.
        // Multiplying the result by 180 / Mathf.PI converts the angle to degrees.
        float x = newDirection.x;
        float y = newDirection.y;
        float rotationAngle = Mathf.Atan2(y, x) * 180 / Mathf.PI;
        //3 Finally, it retrieves the child named Sprite and rotates it rotationAngle degrees along the z-axis.
        // Note that you rotate the child instead of the parent so the health bar — you’ll add it soon — remains horizontal.
        GameObject sprite = (GameObject)
            gameObject.transform.FindChild("Sprite").gameObject;
        sprite.transform.rotation =
            Quaternion.AngleAxis(rotationAngle, Vector3.forward);
    }

    public float distanceToGoal()
    {
        float distance = 0;
        distance += Vector3.Distance(
            gameObject.transform.position,
            waypoints[currentWaypoint + 1].transform.position);
        for (int i = currentWaypoint + 1; i < waypoints.Length - 1; i++)
        {
            Vector3 startPosition = waypoints[i].transform.position;
            Vector3 endPosition = waypoints[i + 1].transform.position;
            distance += Vector3.Distance(startPosition, endPosition);
        }
        return distance;
    }
}

Code is working 100% without errors, BUT.... After each spawn all objects get the same waypoint array. This can be seen on the screen as all objects jump to new waypoint in line together each time new object is spawned. I want the object which is already spawn to live life with it's own array of only once created waypoints.

Fattie
  • 27,874
  • 70
  • 431
  • 719
David
  • 4,332
  • 13
  • 54
  • 93
  • Which error are you getting? – Gunnar B. Mar 20 '16 at 21:45
  • NullReferenceException: Object reference not set to an instance of an object MoveEnemy.Start () (at Assets/Scripts/MoveEnemy.cs:21) – David Mar 20 '16 at 21:54
  • Possible duplicate of [Error when using variable of one class with instance of another](http://stackoverflow.com/questions/36116144/error-when-using-variable-of-one-class-with-instance-of-another) – Fattie Mar 20 '16 at 21:54
  • Try a `Debug.Log(waypoints.Length);` before the for loop. If you don't get any of the further prints, but get no error on those, you probably don't reach them. Also I'd suggest using more differentiated names for variables to make them more explicit and don't run into the chance of mixing them up. (I mean your waypoints var.) – Gunnar B. Mar 20 '16 at 22:20
  • So, your problem is what ChrisF wrote already: you actually give each enemy the same list of waypoints by saying `enemy.waypoints = waypoints`. They need a copy, but they actually don't need gameobjects, `Vector3[] myWay` is sufficient. Also, in your 3.b the `Destroy` needs to be two lines lower or you will get an exception on the audio source. – Gunnar B. Mar 20 '16 at 23:19
  • No thanks, sorry did not enter this site for a while, I've solved it with another question. I've tried the answer from that question and it fixed my problems. http://stackoverflow.com/questions/36152199/declare-object-in-c-sharp-with-x-y-paramateres/36152277?noredirect=1#comment59954534_36152277 Thanks for asking and for your help also! – David Apr 09 '16 at 18:16
  • hi @David you need to TICK someone's answer – Fattie Apr 16 '16 at 16:38

2 Answers2

2

You need to create a new array of waypoints each time you create one from the prefabricated object. You don't show your Instantiate method but I'm guessing that it has a line like this:

this.waypoints = prefab.waypoints;

This will mean that all object you create will share the same list of waypoints (as you've discovered).

What you need is something like this - assuming that the waypoints have X, Y, and Z properties):

this.waypoints = new GameObject[5];
for (int i = 0; i++ ; i < 5)
{
    this.waypoints[i].X = prefab.waypoints[i].X;
    this.waypoints[i].Y = prefab.waypoints[i].Y;
    this.waypoints[i].Z = prefab.waypoints[i].Z;
}

(If you want your points to be a variable length you might want to consider using a list).

This means that each object has a list of unique points even if they start with the same values you can change each independently.

ChrisF
  • 134,786
  • 31
  • 255
  • 325
0

Based on ChrisFs' and Joe Blows' answers, do something like this in your MoveEnemy script:

private Vector3[] myWay;

public void JiggleWaypoints(GameObject[] waypoints)
{
    myWay = new Vector3[waypoints.Length];
    for(int i = 1; i < waypoints.Length; i++)
    {
        myWay[i] = new Vector3(waypoints[i].transform.position.x + Random.Range(-3, 4), waypoints[i].transform.position.y + Random.Range(-3, 4), 0);
    }
}

myWay replaces the GameObject[].

In your SpawnEnemy script you do this:

GameObject e = (GameObject)Instantiate(enemyPrefab);
e.GetComponent<MoveEnemy>().JiggleWaypoints(waypoints);
Gunnar B.
  • 2,879
  • 2
  • 11
  • 17