簡體   English   中英

如何在IEnumerator中等待或等待,然后繼續協程?

[英]How can I waitwhile or waituntil in IEnumerator and then continue the coroutine?

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class NaviConversations : MonoBehaviour
{
    public ObjectsManipulation op;
    public Scaling scaling;
    public ConversationTrigger conversationTrigger;

    private void Update()
    {
        if (DOFControl.hasFinished == true)
        {
            ConversationTrigger.conversationsToPlay.Add(0);
            StartCoroutine(NaviScaling());
            DOFControl.hasFinished = false;
        }
    }

    public IEnumerator NaviScaling()
    {
        // Scaling Up
        if (scaling.objectToScale.transform.localScale == scaling.minSize)
        {
            op.Scaling();
        }
        yield return new WaitUntil

        op.Scaling();
    }
}

在這一部分:

yield return new WaitUntil

我要等待縮放的對象完成縮放:

scaling.objectToScale.transform.localScale == scaling.maxSize

如果是這樣,則繼續繼續並執行以下操作:

conversationTrigger.PlayConversations();

然后再次等待,直到:

conversationTrigger.conversationEnd

是真的。

如果確實如此,請縮減:

op.Scaling();

步驟應為:

  1. 添加對話索引以播放。

  2. 放大。 並等待放大完成。

  3. 開始對話。 然后等待對話結束。

  4. 縮小。

我正在嘗試找到最簡單的等待方法,以及一種可以從任何地方調用public IEnumerator NaviScaling()方法的方法。

更新中的部分:

if (DOFControl.hasFinished == true)

游戲開始時發生一次。

這是op.Scaling使用的腳本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObjectsManipulation : UnityEngine.MonoBehaviour
{
    //Camera
    public Camera playerCamera;

    //Scaling
    public bool canScale = true;
    private Scaling scaling;

    //Lights
    public DimLights dimlights;
    private Coroutine lightCoroutine;

    //Colors
    private Colors colors;

    //Rotating
    public bool stopRotation = false;
    private Rotating rotating;

    private void Start()
    {
        scaling = GetComponent<Scaling>();
        scaling.Inits();

        colors = GetComponent<Colors>();
        colors.Start();

        rotating = GetComponent<Rotating>();
    }

    // Use this for initialization
    void Update()
    {
        if (playerCamera != null)
        {
            //Scaling
            if (Input.GetKeyDown(KeyCode.F) && canScale == true)
            {
                Scaling();
            }
        }

        //Rotate
        if (Input.GetKey(KeyCode.R) && !scaling.scaleUp)
        {
            rotating.x += Time.deltaTime * rotating.rotationSpeed;
            scaling.objectToScale.transform.localRotation = Quaternion.Euler(0, 0, rotating.x);
            rotating.keyPressed = true;
        }
        if (Input.GetKeyUp(KeyCode.R))
        {
            rotating.keyPressed = false;
        }

        if (!rotating.keyPressed && !scaling.scaleUp && rotating.rotateBack == false
            && DetectInteractable.detected == false)
        {
            scaling.objectToScale.transform.rotation = Quaternion.LookRotation(playerCamera.transform.forward);
        }

        if (DetectInteractable.detected == true && !scaling.scaleUp && stopRotation == false)
        {
            rotating.x += Time.deltaTime * rotating.rotationSpeed;
            scaling.objectToScale.transform.localRotation = Quaternion.Euler(0, 0, rotating.x);
        }
    }

    public void Scaling()
    {
        //Flip the scale direction when F key is pressed
        scaling.scaleUp = !scaling.scaleUp;

        //Stop old coroutine
        if (scaling.scaleCoroutine != null)
            StopCoroutine(scaling.scaleCoroutine);

        if (lightCoroutine != null)
            StopCoroutine(lightCoroutine);


        //Scale  up
        if (scaling.scaleUp)
        {
            //Start new coroutine and scale up within 5 seconds and return the coroutine reference
            rotating.rotateBack = false;
            scaling.scaleCoroutine = StartCoroutine(scaling.scaleOverTime(scaling.objectToScale, scaling.maxSize, scaling.duration, playerCamera));
            if (dimlights.lightsOnOff == false)
                lightCoroutine = StartCoroutine(dimlights.dimLightOverTime(1, scaling.duration));
        }

        //Scale Down
        else
        {
            //Start new coroutine and scale up within 5 seconds and return the coroutine reference
            rotating.rotateBack = true;
            scaling.scaleCoroutine = StartCoroutine(scaling.scaleOverTime(scaling.objectToScale, scaling.minSize, scaling.duration, playerCamera));
            if (dimlights.lightsOnOff == false)
                lightCoroutine = StartCoroutine(dimlights.dimLightOverTime(0, scaling.duration)); ;
        }
    }
}

要使用WaitUntil ,您將需要為其提供一種檢查其等待條件的方法。 這是通過將委托傳遞給其構造函數來完成的。

因此,要等到對象仍在縮放時,您將執行以下操作:

yield return new WaitUntil(() => scaling.objectToScale.transform.localScale == scaling.minSize);

注意條件之前的() => ,這會將您的表達式轉換為匿名函數,該函數允許WaitUntil在每個幀上重新評估條件。

您還可以傳遞一個方法作為委托,它看起來很漂亮!

private bool IsFinishedScaling () {
    return scaling.objectToScale.transform.localScale == scaling.minSize;
}

public IEnumerator Example () {
    yield return new WaitUntil(IsFinishedScaling);
    Debug.Log("Scaling has finished!");
}

這應該可以滿足您的需求:

public IEnumerator NaviScaling()
{
    if (scaling.objectToScale.transform.localScale == scaling.minSize)
    {
        op.Scaling();
    }

    while (scaling.objectToScale.transform.localScale != scaling.maxSize)
    {
        yield return null;
    }

    conversationTrigger.PlayConversations();

    while (!conversationTrigger.conversationEnd)
    {
        yield return null;
    }

    op.Scaling();
}

我對到目前為止給出的答案不太滿意。

基本上,問題是如何使用WaitUntil ,它甚至沒有被接受的答案使用 (順便說一句,它提供了一個真正的梅西代碼。)

另一個仍然可以擴展的原因是,兩個答案都基於使用==來檢查相等性。 但是對於Vector3這只是假設

Vector3.Distance(vectorA, vectorB) <= 0.00001f

通常,這對於位置之間的距離非常有用,但對於比例尺,您可能更希望更精確的值。

如果那是目標,並且您不需要比堅持下去更精確。

否則,我寧願使用Mathf.Approximately進行檢查,例如將其作為擴展方法,例如

public static class Vector3Extensio s
{
    public static bool IsSameValue(this Vector3 a, Vector3 b)
    {
        return Mathf.Approximately(Vector3.Distance(a,b), 0f);
    }
}

比使用

yield return new WaitUntil(() => scaling.objectToScale.transform.localScale.IsSameValue(scaling.maxSize));

當然,這很大程度上取決於op.Scaling工作方式,而您並未展示。


或者:(我更願意)

不幸的是,您沒有顯示op.Scaling()功能。 最簡單的方法實際上是使其也成為IEnumerator ,因為您可以簡單地讓它yield return另一個IEnumerator ,這使它執行並自動等待直到僅一行完成。

假設您進行op.Scaling例如

public IEnumerator Scaling(Vector3 targetScale, float duration)
{
    // Get current scale
    var startScale = transform.localScale;

    var timePassed = 0f;
    do
    {
        transform.localScale = Vector3.Lerp(startScale, targetScale, timePassed / duration);

        timePassed += Time.deltaTime;

        yield return null;
    } while(timePassed <= duration);

    transform.localScale = targetScale;
}

你可以做

public IEnumerator NaviScaling()
{
    // Scale up in 1 second and wait
    yield return op.Scaling(scaling.maxSize, 1f);

    // As you can see again this could be a Coroutine so you could directly yield it
    // instead of having to wait for the bool value to turn true
    conversationTrigger.PlayConversations();

    yield return new WaitUntil(() => conversationTrigger.conversationEnd);

    // Scale down in 1 second and wait
    yield return op.Scaling(scaling.minSize, 1f);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM