Как я могу подождать или подождать до IEnumerator, а затем продолжить сопрограмму? - PullRequest
0 голосов
/ 20 мая 2019
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)); ;
        }
    }
}

Ответы [ 3 ]

2 голосов
/ 20 мая 2019

Чтобы использовать 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!");
}
1 голос
/ 20 мая 2019

Я не совсем доволен полученными ответами.

В основном вопрос заключался в том, как использовать 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);
}
1 голос
/ 20 мая 2019

Это должно сделать то, что вы ищете:

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();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...