Как вызывать разные методы только один раз, в разное время?

Я пытаюсь использовать действия и события, счетчики и сопрограммы, но я так запутался.

Цель: заставить MoveCubes() запускаться один раз в течение 3 секунд, а затем заставить LerpSine() запускаться один раз в течение 3 секунд.

Секунды отслеживаются CountdownTimer.cs. Затем SkinnedMeshSpawn.cs взаимодействует с ним.

Таймер обратного отсчета:

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

public class CountdownTimer : MonoBehaviour
{
    float currentTime = 0f;
    float startingTime = 10f;
    public static event Action RaiseReady;
    public static event Action RaiseReady2;
    public SkinnedMeshSpawn SkinnedMeshSpawn;

    void Start()
    {
        currentTime = startingTime;     
        StartCoroutine(UpdateCoroutine());
    }

    IEnumerator UpdateCoroutine()
    {
        while (true)
        {
            SkinnedMeshSpawn.GetComponent<SkinnedMeshSpawn>().MoveCubes();
            currentTime -= 1 * Time.deltaTime; //does it each frame
            int n = Convert.ToInt32(currentTime);

            if (n == 7)
            {
                RaiseReady?.Invoke();
                RaiseReady = null; // clean the event
                yield break; // Kills the coroutine
            }
            yield return new WaitForFixedUpdate();
        }
    }

    IEnumerator UpdateCoroutine2()
    {
        while (true)
        {
            SkinnedMeshSpawn.GetComponent<SkinnedMeshSpawn>().LerpSine();
            currentTime -= 1 * Time.deltaTime; //does it each frame
            int n = Convert.ToInt32(currentTime);

            if (n == 4)
            {
                RaiseReady2?.Invoke();
                RaiseReady2 = null; // clean the event
                yield break; // Kills the coroutine

            }
            yield return new WaitForFixedUpdate();
        }
    }
}

SkinnedMeshSpawn:

using UnityEngine;

[RequireComponent(typeof(SkinnedMeshRenderer))]
public class SkinnedMeshSpawn : MonoBehaviour
{
    public GameObject CubePrefab;
    public GameObject[] objects;
    SkinnedMesh mesh;
    public Rigidbody cubePrefabRb;

    public Vector3[] verts;

    int runOnce = 1;

    void Awake()
    {
        mesh = GetComponent<SkinnedMesh>();
        verts = new Vector3[mesh.vertexCount];
    }
    void Start()
    {
        verts = mesh.vertices;

        CountdownTimer.RaiseReady += CountdownTimer_RaiseReady;
        CountdownTimer.RaiseReady2 += CountdownTimer_RaiseReady2;

        mesh.OnResultsReady += DrawVertices;
    }
    void CountdownTimer_RaiseReady()
    {
        Debug.Log("Done");
        CountdownTimer.RaiseReady -= CountdownTimer_RaiseReady; // Remove listener though the other class is already clearing it
    }

    private void CountdownTimer_RaiseReady2()
    {
        Debug.Log("Done2");
        CountdownTimer.RaiseReady2 -= CountdownTimer_RaiseReady; // Remove listener though the other class is already clearing it
    }

    void DrawVertices(SkinnedMesh mesh)
    {
        if (runOnce == 1)
        {
            for (int i = 0; i < mesh.vertexCount; i++)
            {
                Vector3 position = verts[i];
                var cubeClone = Instantiate(CubePrefab, position, transform.rotation);
                cubeClone.tag = "CubePFInst";
            }
            runOnce = 0;
        }
    }


    public void MoveCubes()
    {
        if (runOnce == 0)
        {
            objects = GameObject.FindGameObjectsWithTag("CubePFInst");

            for (int i = 0; i < mesh.vertexCount; i++)
            {
                Vector3 position = verts[i];
                cubePrefabRb = objects[i].GetComponent<Rigidbody>();
                cubePrefabRb.MovePosition(Vector3.Lerp(position, position, Time.deltaTime * 6));
            }
        }
    }

    public void LerpSine()
    {
        Debug.Log("LerpSine");
    }
}

Максимум, что мне удалось сделать до сих пор, это вызвать UpdateCoroutine2 и вывести Done2 в журнал, но LerpSine печатается многократно, как будто я запускаю сопрограмму с каждым обновлением кадра.

Я был бы признателен, если бы кто-нибудь мог просмотреть код и дать предложения о том, как достичь цели, указанной выше. Позже я хотел реализовать GameManager, но это уже становится очень сложным.


person rashapou    schedule 10.07.2019    source источник
comment
Я не вижу, как вызывается UpdateCoroutine2.   -  person Ruzihm    schedule 10.07.2019
comment
ОК, событие похоже на OnClick, в сокращенной версии Action - это то, что вызывается в результате клика (есть и другие причины), так что это совсем не то, что вам нужно.. и то, как вы вызываете UpdateCoroutine2, не включено в предоставленном коде .. вы поместили его в обновление?   -  person BugFinder    schedule 10.07.2019
comment
Моих попыток нет в приведенном коде, потому что они очень запутались; Я вытащил их и оставил то, что у меня было. Да, я поместил его в функцию обновления, потому что не знал, как вызвать что-то после того, как код уже запущен, кроме этого. Ну, я также попытался реализовать другой IEnumerator и вызвать UpdateCoroutine2, когда он достиг определенного времени, но по какой-то причине это также вызывало его неоднократно. Я попытаюсь написать это снова, как у меня было в моей последней попытке, но я не знаю, как я должен попытаться что-то изменить.   -  person rashapou    schedule 11.07.2019
comment
Он вызывает повторно, потому что он находится в цикле while, который повторяет каждое фиксированное обновление в течение 3 секунд...   -  person Ruzihm    schedule 11.07.2019


Ответы (1)


Использование событий здесь действительно слишком усложняет то, что вы, кажется, хотите сделать.

Я бы использовал yield return new WaitForSeconds(seconds); для определения времени:

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

public class CountdownTimer : MonoBehaviour
{

    public SkinnedMeshSpawn SkinnedMeshSpawn;

    void Start()
    { 
        StartCoroutine(FunctionCaller(3f,3f));
    }

    IEnumerator FunctionCaller(float pause1, float pause2)
    {
        SkinnedMeshSpawn.GetComponent<SkinnedMeshSpawn>().MoveCubes();

        yield return new WaitForSeconds(pause1);

        SkinnedMeshSpawn.GetComponent<SkinnedMeshSpawn>().LerpSine();

        yield return new WaitForSeconds(pause2);

        // Do whatever after pause 2
    }
}
person Ruzihm    schedule 11.07.2019
comment
Большое спасибо. Это имеет больше смысла. - person rashapou; 12.07.2019