【问题标题】:How can I wait number of seconds before changing for new random speed? [duplicate]如何在更改新的随机速度之前等待几秒钟? [复制]
【发布时间】:2019-01-07 04:34:49
【问题描述】:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GateControl : MonoBehaviour
{
    public Transform door;
    public float doorSpeed = 1.0f;
    public bool randomDoorSpeed = false;
    [Range(0.3f, 10)]
    public float randomSpeedRange;

    private Vector3 originalDoorPosition;

    // Use this for initialization
    void Start()
    {
        originalDoorPosition = door.position;
    }

    // Update is called once per frame
    void Update()
    {
        if (randomDoorSpeed == true && randomSpeedRange > 0.3f)
        {
            StartCoroutine(DoorSpeedWaitForSeconds());
        }
        door.position = Vector3.Lerp(originalDoorPosition,
            new Vector3(originalDoorPosition.x, originalDoorPosition.y, 64f),
            Mathf.PingPong(Time.time * doorSpeed, 1.0f));
    }

    IEnumerator DoorSpeedWaitForSeconds()
    {
        doorSpeed = Random.Range(0.3f, randomSpeedRange);

        yield return new WaitForSeconds(3);
    }
}

在 Update 中创建 StartCoroutine 是个坏主意。但是我希望它在运行游戏时会采用一个随机速度,然后等待 3 秒并更改为新的随机速度,然后再等待 3 秒并更改为另一个新的随机速度等等。

同时等待 3 秒以保持当前速度不变,直到下一次更改。

更新:

这是我尝试过的:

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

public class GateControl : MonoBehaviour
{
    public Transform door;
    public float doorSpeed = 1.0f;
    public bool randomDoorSpeed = false;
    public bool IsGameRunning = false;
    [Range(0.3f, 10)]
    public float randomSpeedRange;

    private Vector3 originalDoorPosition;

    // Use this for initialization
    void Start()
    {
        IsGameRunning = true;
        originalDoorPosition = door.position;

        StartCoroutine(DoorSpeedWaitForSeconds());
    }

    // Update is called once per frame
    void Update()
    {
        door.position = Vector3.Lerp(originalDoorPosition,
            new Vector3(originalDoorPosition.x, originalDoorPosition.y, 64f),
            Mathf.PingPong(Time.time * doorSpeed, 1.0f));
    }

    IEnumerator DoorSpeedWaitForSeconds()
    {
        var delay = new WaitForSeconds(3);//define ONCE to avoid memory leak
        while (IsGameRunning)
        {
            if (randomDoorSpeed == true && randomSpeedRange > 0.3f)
                doorSpeed = Random.Range(0.3f, randomSpeedRange);

            yield return delay;
        }
    }
}

但是有两个问题。

第一个问题是每 3 秒,当它改变门的速度时,它也会从当前位置改变门的位置。所以看起来门的位置正在跳到另一个位置,然后从那里继续。我怎样才能让它在门从当前位置移动的同时改变速度?

第二个问题是如何更改 randomDorrSpeed 标志,使其在游戏运行时生效?我希望如果 randomDorrSpeed 为假,则使用门的原始速度(1.0),如果为真,则使用随机速度。

【问题讨论】:

  • 考虑在您的Update 方法中进行计算以确定自上次更改以来经过了多少秒,您的随机方法很好。我会用DateTime.Now - lastChange 跟踪它。
  • 三秒后你能启动一个外部线程来引发事件或更新共享变量吗?
  • @snowCrabs 我不会为此使用外螺纹。有很多更好的选择。
  • 关于第二个问题的一个问题。您需要检查游戏是否正在运行?我的意思是如果你在脚本中是因为游戏正在运行。在什么情况下你认为 randomDorrSpeed 可能是假的?
  • @IgnacioAlorre 我可以使用 while(true) 而不是 while(isgamerunning) 所以我根本不需要 isgamerunning。并且 randomDoorSpeed 是公共的,如果它是假的,它将使用原始的恒定速度 1,如果它是真的,它将使用随机速度。看看 Bijan 解决方案的答案。所以我不需要 IsGameRunning 但 randomDoorspeed 是决定是否使用随机速度。

标签: c# unity3d


【解决方案1】:

你已经知道协程应该从Start开始:

void Start()
{
     //initialization
     StartCoroutine(DoorSpeedWaitForSeconds());
}

所以让协程成为一个具有适当终止条件的循环:

IEnumerator DoorSpeedWaitForSeconds()
{
    var delay = new WaitForSeconds(3);//define ONCE to avoid memory leak
    while(IsGameRunning)
    {
        if(randomDoorSpeed == true && randomSpeedRange > 0.3f)
            doorSpeed = Random.Range(0.3f, randomSpeedRange);

        if(!randomDoorSpeed)
            doorSpeed = 1;//reset back to original value

        yield return delay;//wait
    }
}

对于您提出的另一个问题,如果您考虑一下,您不可能使用基于 Time.time 的动态速度的乒乓球。你需要像这样改变它:

bool isRising = true;
float fraq = 0;
void Update()
{
    if (isRising)
        fraq += Time.deltaTime * doorSpeed;
    else
        fraq -= Time.deltaTime * doorSpeed;

    if (fraq >= 1)
        isRising = false;
    if (fraq <= 0)
        isRising = true;

    fraq = Mathf.Clamp(fraq, 0, 1);


    door.position = Vector3.Lerp(originalDoorPosition,
        new Vector3(originalDoorPosition.x, originalDoorPosition.y, 64f),
        fraq);
}

【讨论】:

  • 它正在工作,但我更新了我的问题,用两个子问题编辑了我的问题。当速度随机变化时,门会从当前位置变为另一个位置,就像门“跳”到新位置一样。我希望门从当前位置继续,但以新的速度。
  • @BenziAvrumi 好的。我更新了我的答案,请看一下。
【解决方案2】:

不用协程也可以解决原来的问题:

public float timeBetweenChangeSpeed = 3f;
public float timer = 0;

void Update ()
{
    // Add the time since Update was last called to the timer.
    timer += Time.deltaTime;

    // If 3 seconds passed, time to change speed
    if(timer >= timeBetweenChangeSpeed)
    {
        timer = 0f;
        //Here you call the function to change the random Speed (or you can place the logic directly)
        ChangeRandomSpeed();
    }

}

关于开门和关门。这是我在玩过的迷宫游戏中用来控制门的脚本:

您需要设置空的游戏对象来设置边界,即直到您想要将门移动一次打开或关闭时。您将这个空的游戏对象放在场景中,并将它们链接到正确字段中的脚本。该脚本将自行采用 transform.position 组件。当角色接近时,还有一个触发器进入以激活门。如果你不需要那部分,我明天可以编辑代码。

您也可以使用此脚本来移动平台、敌人……通常是任何可以直线移动的东西。

using UnityEngine;
using System.Collections;

public class OpenDoor : MonoBehaviour {

    // define the possible states through an enumeration
    public enum motionDirections {Left,Right};
    // store the state
    public motionDirections motionState = motionDirections.Left;

    //Variables for State Machine
    bool mOpening = false;
    bool mClosing = false;

    //bool mOpened = false;

    //OpenRanges to open/close the door
    public int OpenRange = 5;
    public GameObject StopIn;   
    public GameObject StartIn;

    //Variables for Movement
    float SpeedDoor = 8f;
    float MoveTime = 0f;    

    int CounterDetections = 0;


    void Update () {
        // if beyond MoveTime, and triggered, perform movement
        if (mOpening || mClosing) {/*Time.time >= MoveTime && */
            Movement();
        }
    }

    void Movement()
    {
        if(mOpening)
        {
            transform.position = Vector3.MoveTowards(transform.position, StopIn.transform.position, SpeedDoor * Time.deltaTime);

            if(Vector3.Distance(transform.position, StopIn.transform.position) <= 0)
                mOpening = false;

        }else{ //This means it is closing

            transform.position = Vector3.MoveTowards(transform.position, StartIn.transform.position, SpeedDoor * Time.deltaTime);

            if(Vector3.Distance(transform.position, StartIn.transform.position) <= 0)
                mClosing = false;

        }
    }

    // To decide if door should be opened or be closed
    void OnTriggerEnter(Collider Other)
    {
        print("Tag: "+Other.gameObject.tag);

        if(Other.gameObject.tag == "Enemy" || Other.gameObject.tag == "Player" || Other.gameObject.tag == "Elevator")
        {
            CounterDetections++;
            if(!mOpening)
                Opening();
        }       
    }

    void OnTriggerStay(Collider Other)
    {
        if(Other.gameObject.tag == "Elevator")
        {
            if(!mOpening)
                Opening();
        }
    }

    void OnTriggerExit(Collider Other)
    {
        if(Other.gameObject.tag == "Enemy" || Other.gameObject.tag == "Player")
        {
            CounterDetections--;
            if(CounterDetections<1)
                Closing();
        }
    }

    void Opening()
    {
        mOpening = true;
        mClosing = false;
    }

    void Closing()
    {
        mClosing = true;
        mOpening = false;
    }
}

【讨论】:

    【解决方案3】:

    使用计时器并设置时间间隔。每次达到间隔时,都会触发委托事件。

        var t = new Timer {Interval = 3000};
        t.Elapsed += (sender, args) => { /* code here */};
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-20
      • 2016-02-14
      • 1970-01-01
      • 1970-01-01
      • 2014-12-04
      相关资源
      最近更新 更多