简体   繁体   中英

Pass collision to an IEnumerator to handle clean up of dynamic function result

I am trying to learn unity. This is something I would use in Javascript so I was hoping to find a way to do this in C#, where you take the collision variable and use the reference to have another function clean up the variables after you are finished.

private void OnTriggerEnter(Collider collision) {
    if(collision.gameObject.CompareTag("Enemy")) {
        collision.gameObject.GetComponent<enemy>().powerup = 1;

        StartCoroutine(removePower(collision.gameObject.GetComponent<enemy>()));
        Destroy(gameObject);
    }

    if (collision.gameObject.CompareTag("Player")) {
        collision.gameObject.GetComponent<player>().powerup = 1;
        

        StartCoroutine(removePower(collision.gameObject.GetComponent<player>()));
        Destroy(gameObject);
    }
}

IEnumerator removePower(GameObject target) {
    yield return new WaitForSeconds(5);
    target.powerup = 0;
}

Note: Coroutines are also stopped when the MonoBehaviour is destroyed or if the GameObject the MonoBehaviour is attached to is disabled.

You should destroy the gameobject when the coroutine finishes.

StartCoroutine(removePower(collision.gameObject.GetComponent<enemy>()));
//Destroy(gameObject);

IEnumerator removePower(GameObject target) {
    yield return new WaitForSeconds(5);
    target.powerup = 0;
    Destroy(gameObject);
}

Or run the coroutine on another gameobject

var enemy = collision.gameObject.GetComponent<enemy>();
enemy.StartCoroutine(removePower(enemy));

First if all there is a general flaw in your approach: When you

 Destroy(gameObject);

this object this component is attached to then also all Coroutines are immediately canceled.

I would therefore start the coroutine rather on the target itself.

And then your classes should have a common interface or base class like for example

public abstract class Character : MonoBehaviour
{
    public float powerup;

    // And other common members
}

And then you inherit

public class Player : Character 
{
    // Additional player specific stuff
}

and

public class Enemy : Character
{
    // Additional enemy specific stuff
}

OR if you rather want to go for an interface

public interface ICharacter
{
    float powerup { get; set; }
}

And then both your classes have to implement that

public class Player : MonoBehaviour, ICharacter 
{
    public float powerup { get; set; }

    // Additional player specific stuff
}

and

public class Enemy : MonoBehaviour, ICharacter 
{
    public float powerup { get; set; }

    // Additional player specific stuff
}

And then your collision code could simply be

private void OnTriggerEnter(Collider collision) 
{
    // TryGetComponent now finds anything inherited from Character
    // you don't even need to check the tags
    if(collision.TryGetComponent<Character>(out var character)) 
    // Or if using the interface
    //if(collision.TryGetComponent<ICharacter>(out var character)
    {
        // Let the character run this coroutine without even having to know what it does
        character.StartCoroutine(PowerUpRoutine(character));
        Destroy(gameObject);
    }
}

IEnumerator PowerUpRoutine(Character target) 
{
    target.powerup = 1;
    yield return new WaitForSeconds(5);
    target.powerup = 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM