【问题标题】:How to call different methods only once, at different times?如何在不同的时间只调用一次不同的方法?
【发布时间】:2019-07-10 18:55:33
【问题描述】:

我正在尝试使用 Actions 和 Events、Inumerators 和 Coroutines,但我很困惑。

目标:让 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 打印到 Log,但 LerpSine 会重复打印,就好像我在每一帧都启动协程一样更新。

如果有人可以查看代码并就如何实现上述目标提出建议,我将不胜感激。后来我想实现一个 GameManager 但这已经变得非常复杂了。

【问题讨论】:

  • 我无法看到UpdateCoroutine2 是如何被调用的。
  • OK 一个事件就像“OnClick”,作为一个简短的版本,Action 是由于点击而被调用的东西(还有其他原因),所以这根本不是你需要的。 . 以及您如何调用 UpdateCoroutine2 未包含在提供的代码中.. 您是否将其放入更新中?
  • 我的尝试不在列出的代码中,因为它们变得非常混乱;我把它们拿出来,留下了我剩下的东西。是的,我把它放在了 Update 函数中,因为我不知道在代码已经运行之后如何调用其他东西。好吧,我确实也尝试过实现 another IEnumerator 并在达到某个时间时调用UpdateCoroutine2,但由于某种原因也反复调用它。我会再次尝试写下我上次尝试的方式,但我不知道应该如何尝试改变。
  • 它在重复调用,因为它在一个while 循环中,每个固定更新重复 3 秒...

标签: c# unity3d events action coroutine


【解决方案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
    }
}

【讨论】:

  • 非常感谢。这更有意义。
猜你喜欢
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-25
  • 2013-09-14
  • 2017-01-26
相关资源
最近更新 更多