首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >协程WaitForSeconds

协程WaitForSeconds
EN

Stack Overflow用户
提问于 2021-06-11 11:45:00
回答 2查看 74关注 0票数 0

我的代码有问题吗?

代码语言:javascript
复制
public class Vaccine : MonoBehaviour
{
    public GameObject pickupEffect;

    public Score currentScore;
    public float BonusScore;
    private float immuneTime = 5f;
    public PlayerMotor player;
    private IEnumerator tookVaccineCo;

    private void Start()
    {
        currentScore = FindObjectOfType<Score>();
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            var player = other.GetComponent<PlayerMotor>();
            Pickup();
            TookVaccine(player);
        }
    }


    private void TookVaccine(PlayerMotor playerMotor)
    {
        if (tookVaccineCo != null)
            StopCoroutine(tookVaccineCo);
        tookVaccineCo = TookVaccineEnum(playerMotor);
        StartCoroutine(tookVaccineCo);

    }

    IEnumerator TookVaccineEnum(PlayerMotor playerMotor)
    {
        playerMotor.isImmune = true;
        yield return new WaitForSeconds(immuneTime);
        playerMotor.isImmune = false;
    }

    void Pickup()
    {
        currentScore.CurrentScore = currentScore.CurrentScore + BonusScore;
        //apply effect for player


        //remove power up object
        Destroy(gameObject);
    }
}
EN

回答 2

Stack Overflow用户

发布于 2021-06-11 12:30:25

你做了

代码语言:javascript
复制
Destroy(gameObject);

负责执行协程->的对象永远不会结束。

选项A-将例程移动到播放器中

例如,您可以在播放器上有一个专用的组件,如下所示

代码语言:javascript
复制
public class ImmunityController : MonoBehaviour
{
    [SerializeField] private PlayerMotor _motor;

    private void Awake ()
    {
        if(!_motor) _motor = GetComponent<PlayerMotor>();
    }

    private Coroutine _current;

    public void SetImmune(float immuneTime)
    {
        if(_current) StopCoroutine(_current);

        _current = StartCoroutine (ImmuneRoutine (immuneTime));
    }

    private IEnumerator ImmuneRoutine(float immuneTime)
    {
        _motor.isImmune = true;

        yield return new WaitForSeconds (immuneTime);

        _motor.isImmune = false;
    }
}

现在让你的拾取对象只启动那个例程

代码语言:javascript
复制
public class Vaccine : MonoBehaviour
{
    public GameObject pickupEffect;

    public Score currentScore;
    public float BonusScore;
    private const float immuneTime = 5f;

    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player") && other.TryGetComponent<ImmuneController>(out var player))
        {
            // only tell the player that he took a vaccine - the rest is his own responsibility
            player.SetImmune(immuneTime);
            currentScore.CurrentScore = currentScore.CurrentScore + BonusScore
            Destroy (gameObject);
        }
    }
}

这样你就解耦了责任--我更喜欢这个选项。

选项B-仅将StartCoroutine移动到播放器

另一种选择--虽然在我看来有点“脏”--是让玩家自己执行协程,而你仍然在Vaccine脚本中实现它!

但是,这只有在确实需要“混淆”一点玩家正在执行的东西时才有意义,这样玩家对象就不会确切地知道Vaccine导致了什么。

这将是一些简单的更改,而不需要新的脚本。

在PlayerMotor中有一个附加字段

代码语言:javascript
复制
public Coroutine tookVaccineCo;

然后做

代码语言:javascript
复制
public class Vaccine : MonoBehaviour
{
    public GameObject pickupEffect;

    public Score currentScore;
    public float BonusScore;

    private float immuneTime = 5f;

    public PlayerMotor player;

    private void Start()
    {
        currentScore = FindObjectOfType<Score>();
    }

    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player") && other.TryGetComponent<PlayerMotor>(out var player)
        {
            Pickup();
            TookVaccine(player);
        }
    }


    private void TookVaccine(PlayerMotor playerMotor)
    {
        // Magic! Simply let the player execute this routine without the need 
        // for letting him know what he is executing exactly
        // For correctly stopping the routine also let the player itself 
        // store the currently running routine
        if (player.tookVaccineCo != null) player.StopCoroutine(player.tookVaccineCo);

        
        player.tookVaccineCo = player.StartCoroutine(TookVaccineEnum(player, immuneTime)); 
    }

    // Also this is now "shared" between all instances
    // Wouldn't be necessary in the current state BUT if you are ever going to use something 
    // related to a specific instance of this script 
    // then you would have troubles -> now you simply can't do that by accident
    private static IEnumerator TookVaccineEnum(PlayerMotor playerMotor, float time)
    {
        playerMotor.isImmune = true;
        yield return new WaitForSeconds(time);
        playerMotor.isImmune = false;
    }

    void Pickup()
    {
        currentScore.CurrentScore = currentScore.CurrentScore + BonusScore;

        Destroy(gameObject);
    }
}

这样,Vaccine对象也不会有问题,因为例程本身实际上是由player对象执行的。

选项C-禁用组件并在以后销毁

只需先禁用所有相关组件即可。然后等待销毁,直到协程结束。

代码语言:javascript
复制
public class Vaccine : MonoBehaviour
{
    [SerializeField] private Renderer _renderer;
    [SerializeField] private Collider _collider;

    public GameObject pickupEffect;

    public Score currentScore;
    public float BonusScore;
    private float immuneTime = 5f;
    public PlayerMotor player;

    private Coroutine tookVaccineCo;

    private void Start()
    {
        if(!currentScore)currentScore = FindObjectOfType<Score>();

        if(!_renderer) _renderer = GetComponent<Renderer>();
        if(!_collider) _collider = GetComponent<Collider>();
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player") && other.TryGetComponent<PlayerMotor>(out var player))
        {
            Pickup();
            TookVaccine(player);
        }
    }

    private void TookVaccine(PlayerMotor playerMotor)
    {
        if (tookVaccineCo != null)                StopCoroutine(tookVaccineCo);

        tookVaccineCo = StartCoroutine(tookVaccineCo);
    }

    private IEnumerator TookVaccineEnum(PlayerMotor playerMotor)
    {
        playerMotor.isImmune = true;
        yield return new WaitForSeconds(immuneTime);
        playerMotor.isImmune = false;

        // Now finally destroy this object
        Destroy(gameObject);
    }

    void Pickup()
    {
        currentScore.CurrentScore = currentScore.CurrentScore + BonusScore;

        // ONLY disable power up object
        _renderer.enabled = false;
        _collider.enabled = false;
    }
}
票数 1
EN

Stack Overflow用户

发布于 2021-06-11 12:16:34

您正在使用Destroy(gameObject);销毁void Pickup()中的Vaccine实例游戏对象。这似乎不是一个好主意。如果在输入触发器时执行Destroy(gameObject);

代码语言:javascript
复制
void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Player"))
        {
            var player = other.GetComponent<PlayerMotor>();
            Pickup(); //this calls Destroy(gameObject);
            TookVaccine(player);
        }
    }

保存您的Vaccine monobehaviour实例的当前游戏对象被销毁,因此放在其中的逻辑将不再起作用。以防这可能是您遇到的问题。

我认为你需要从一个脚本中处理玩家的免疫力,这个脚本的主游戏对象不会被销毁,这个脚本处理玩家的行为(在你的例子中,认为它可能是PlayerMotor似乎是一个好主意,而不是Vaccine

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67931007

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档