Unity:如何按时间延迟按钮调用?

Unity: How to Delay button call by time?

我希望每次用户单击 UI 按钮时将浮点数递增 0.5,如果用户按下按钮超过 2 秒,我希望将浮点数连续递增 0.5,为此我使用事件触发器(PointerDown、PointerUp)并调用更新中的函数。当我使用下面的代码时,我无法连续增加浮点值。

更新代码

void Update () {
    transform.rotation = Quaternion.Lerp (qStart, qEnd, (Mathf.Sin(Time.time * speed) + 1.0f) / 2.0f);

    if(Time.timeScale == 0)
        transform.rotation =  Quaternion.Euler(0,0,0);

    clickCondition ();      
}

PointerDown 函数

public void WhenIncreaseClicked()
{ 
    if (timeDown < 2.0f)
        IncreaseBPM ();
    else
        increase = true;    
}

PinterUp 函数

public void WhenIncreaseNotClicked()
{ 
    increase = false; 
    Time.timeScale = 1;
}

增加BPM

public void IncreaseBPM()
{
    if (speed < 12) 
    {
        speed += 0.05f;
        bpmText.GetComponent<BeatTextControl> ().beats += 1;
        PlayerPrefs.SetFloat ("savedBPM", speed);
    } 
}

点击条件

public void clickCondition()
{   
    if(increase)
    { 
        IncreaseBPM();
    }
    else if(decrease)
    { 
        DecreaseBPM();
    }
}

开始

void Start () {
    qStart = Quaternion.AngleAxis ( angle, Vector3.forward);
    qEnd   = Quaternion.AngleAxis (-angle, Vector3.forward);

    timeDown = Time.deltaTime;

    if (PlayerPrefs.HasKey ("savedBPM"))
        speed = PlayerPrefs.GetFloat ("savedBPM");
    else
        speed = 1.5f;
}

我在Start()中设置了timeDown = Time.deltaTime

假设没有其他代码更改您的 increase 变量,您将无法连续递增它,因为它永远不会设置为 true

Start() 中有一行 timeDown = Time.deltaTime;,因此 timeDown 将等于自上一帧以来的秒数。这不仅是一个问题,因为 timeDown 永远不会改变(Start() 只被调用一次),而且这是一个问题,因为它不可能超过 2.0f,因为单帧是极不可能的需要 2 秒才能完成。它通常是一个非常小的数字,例如 0.06f.

因此,在您的 WhenIncreaseClicked() 方法中,if (timeDown < 2.0f) 将始终等于 true。因此,永远不会执行 else 子句,并且 increase 永远不会设置为 true。

要解决这个问题,您可以创建一个新的布尔变量,例如clicked 并在 WhenIncreaseClicked() 开始时将其设置为 true,在 WhenIncreaseNotClicked() 开始时将其设置为 false。然后在 Update() 中,如果 clickedtrue,您可以将 Time.deltaTime 添加到 timeDown。您还需要将 if/else 移到 WhenIncreaseClicked() 之外,并移到 Update() 中,确保当 clicked 是 [=14= 时它只是 运行 ].

例如:

void Update () {
    transform.rotation = Quaternion.Lerp (qStart, qEnd, (Mathf.Sin(Time.time * speed) + 1.0f) / 2.0f);

    if(Time.timeScale == 0)
        transform.rotation =  Quaternion.Euler(0,0,0);

    if(clicked) {
        timeDown += Time.deltaTime;
        if (timeDown >= 2.0f) // note the >= not <
            increase = true;
    }
    clickCondition ();

}

WhenIncreaseClicked()

public void WhenIncreaseClicked()
{ 
    clicked = true;
    IncreaseBPM();   
}

WhenIncreaseNotClicked()

public void WhenIncreaseNotClicked()
{ 
    clicked = false;
    increase = false;
    Time.timeScale = 1;
}

您还可以在 Start() 中删除对 timeDown 的分配,因为它没有用。

首先,Unity 文档说 Time.deltaTime

The time in seconds it took to complete the last frame.

当您设置 timeDown = Time.deltaTime 时,timeDown 变为 微小的 分数,例如 0.01621689。因此,timeDown < 2.0f 总是 returns true 并且您的代码永远不会到达 increase = true; 行。

你应该知道的第二点是Time.time

The time at the beginning of this frame (Read Only). This is the time in seconds since the start of the game.

您在 Update() 方法中使用 Time.time 作为 Mathf.Sin(Time.time * speed)。请记住,Time.time 可以是足够大的数字,表示文档中提到的自游戏开始以来的秒数。当您执行 Time.time * speed 时,输出数字可能会很大(假设 speed > 1),从而导致一些问题。幸运的是,您在 Mathf.Sin() 中使用它,您只能在 [0, 1] 之间获得数字。可能,您打算改用 Time.deltaTime


让我们记住Time.time:

The time in seconds since the start of the game

您可以使用它来检查时差。

float lastDownTime;
bool isDown;


void OnPointerDown() // Method name itself says when it should be called
{
    lastDownTime = Time.time;
    isDown = true;
}


void OnPointerUp()
{
    isDown = false;
}


void Update () 
{
    if (isDown)
    {
        if  (Time.time - lastDownTime  > 2) // 2 seconds
        {
            IncreaseBPM ();
        }
    }
}

注意: Unity 说 Time.timeScale

Except for realtimeSinceStartup, timeScale affects all the time and delta time measuring variables of the Time class.

因此,如果您坚持使用 Time.timeScale,而不是使用 Time.time,您应该在上面的示例中使用 Time.realtimeSinceStartup