Rohit Hooda
Rohit Hooda

Reputation: 13

Change movement of a instantiated GameObject from next instantiation

I'm using Unity and C#.

In my game, enemies are instantiated repeatedly and move towards the player in linear path. I want to make the movement of enemy in sine wave after some specific time has elapsed, to make game tougher.

The movement changes instantly, but I want the change to come in effect from instantiation of new(next) enemy and not to the ones currently present.

What can I do?

EnemySpawner script -

private void Start()
{
    timeelapsed = 0f;
    StartCoroutine(SpawnEnemies(delay));
}
private void Update()
{
    timeelapsed += Time.deltaTime;
}
private IEnumerator SpawnEnemies(float delay)
{
    while (true)
    {
        SpawnNewEnemy();
        yield return new WaitForSeconds(delay);
    }
}
private void SpawnNewEnemy()
{
    if (!enemyclone)
    {
        enemyclone = Instantiate(enemy, enemySpawner.transform.position + offset, Quaternion.identity);
    }
}

Enemy Movement Script:

private void Update()
{
    t = Time.time;
    if (EnemySpawner.timeelapsed > 0f && EnemySpawner.timeelapsed <= 20f)
    {
        enemy.transform.Translate(Vector3.forward * speed * Time.deltaTime);
    }
    if (EnemySpawner.timeelapsed > 20f && EnemySpawner.timeelapsed <= 40f)
    {
        enemy.GetComponent<Rigidbody>().velocity = Vector3.forward * 5 + Vector3.left * 3 * Mathf.Sin(10f * t);
    }
}

Upvotes: 0

Views: 168

Answers (2)

Milan Egon Votrubec
Milan Egon Votrubec

Reputation: 4049

Knowing now that the request was for "waves" of enemies, we need to add the wave defining items to each enemy. Therefore, modifying first the EnemyMovement script:

public class EnemyMovement : MonoBehaviour
{
    public enum MovementType
    {
        None = 0,
        Linear = 1,
        Sinusoidal = 2
        // etc, etcc
    }

    /// <summary>
    /// Movement affects the movement type of the enemy.
    /// </summary>
    public MovementType Movement { get; set; }

    /// <summary>
    /// This affects the Speed of the Enemy. Used in conunction with Movement to
    /// produce the enenmy's wave movement type.
    /// </summary>
    public float Speed { get; set; }

    private Rigidbody rigidBody;


    private void Awake ( )
    {
        rigidBody = GetComponent<Rigidbody> ( );
    }


    private void Update ( )
    {
        switch ( Movement)
        {
            case MovementType.Linear:
                transform.Translate ( Vector3.forward * Speed * Time.deltaTime );
                break;
            case MovementType.Sinusoidal:
                // You probably want the Speed property to affect this as well...
                rigidBody.velocity = Vector3.forward * 5 + Vector3.left * 3 * Mathf.Sin ( 10f * Time.time );
                break;

           // Any extra movement types you want here...
        }

    }
}

And then the EnemySpawner script to drive the Enemy instantiation:

public class EnemySpawner : MonoBehaviour
{
    public float Delay;
    public float StartSpeed;

    public GameObject enemy;
    public GameObject enemySpawner;
    public Vector3 offset;

    private float timeElapsed;
    private float currentSpeed;
    private EnemyMovement.MovementType currentMovement;


    void Start ( )
    {
        timeElapsed = 0f;
        currentSpeed = StartSpeed;
        StartCoroutine ( SpawnEnemies ( Delay ) );
        currentMovement = EnemyMovement.MovementType.Linear;
    }


    void Update ( )
    {
        timeElapsed += Time.deltaTime;

        // We can determine at what time the Wave parameters change here.
        if ( timeElapsed >= 40.0f )
        {
            currentSpeed += 10.0f; // Add speed, for example.
        }
        else if ( timeElapsed >= 20.0f )
        {
            currentMovement = EnemyMovement.MovementType.Sinusoidal;
        }
    }


    IEnumerator SpawnEnemies ( float delay )
    {
        while ( true )
        {
            var enemyClone = Instantiate ( enemy, enemySpawner.transform.position + offset, Quaternion.identity );
            var movement = enemyClone.GetComponent<EnemyMovement> ( );

            // We now set what the enemy uses as the Wave values.
            movement.Speed = currentSpeed;
            movement.Movement = currentMovement;

            yield return new WaitForSeconds ( delay );
        }
    }
}

Upvotes: 0

Milan Egon Votrubec
Milan Egon Votrubec

Reputation: 4049

There's a thousand ways to accomplish this, but one I think might be easy to implement and understand might be to set up Action that is fired when you instantiate a new enemy from the spawner. I've quickly written up a few changes to your EnemySpawner and EnemyMovement scripts that I think might help you.

First, EnemySpawner:

public static event Action EnemySpawning;
void SpawnNewEnemy ( )
{
    if ( !enemyclone )
    {
        EnemySpawning?.Invoke ( );
        enemyclone = Instantiate ( enemy, enemySpawner.transform.position + offset, Quaternion.identity );
    }
}

Now, the EnemyMovement:

private bool travelInLinearPath = true;

private void OnEnable ( )
{
    EnemySpawner.EnemySpawning -= OnEnemySpawning;
    EnemySpawner.EnemySpawning += OnEnemySpawning;
    travelInLinearPath = true;
}

public void OnEnemySpawning( )
{
    EnemySpawner.EnemySpawning-= OnEnemySpawning;
    travelInLinearPath = false;
}

private void Update ( )
{
    if ( travelInLinearPath )
        enemy.transform.Translate ( Vector3.forward * speed * Time.deltaTime );
    else
        enemy.GetComponent<Rigidbody> ( ).velocity = Vector3.forward * 5 + Vector3.left * 3 * Mathf.Sin ( 10f * Time.time );
}

Every time you enable an enemy, you're asking to be notified when the NEXT enemy is about to be spawned. When this happens, you tell THIS enemy to change from linear, to sinusoidal movement (travelInLinearPath). You also ask that this enemy not be notified anymore when a new enemy is spawned (unless you re-enable this enemy).

I've also not gone into whether you should be grabbing a new enemy from a pool of enemy objects. But the hope that you do is why I added the removal and re-enrolling in the event in OnEnable(). You might want/need to place that code within Start() instead depending on your enemy instantiation and creation later in the game.

Upvotes: 0

Related Questions