【问题标题】:Only use button every few seconds in Unity [duplicate]在 Unity 中每隔几秒才使用一次按钮 [重复]
【发布时间】:2021-05-31 00:10:25
【问题描述】:

我正在尝试使 Unity 中的按钮每隔几秒钟才能按下和激活。我有一个带有名言的数组,当我按下按钮时,它确实会显示这些名言,但如果你连续按下按钮,它将循环浏览所有名言,而无法深思熟虑并阅读它们。现在,我尝试了类似下面的方法,但它什么也没做(因为按钮仍然可以按下并且没有明显效果):

Bool pressed;

void Function () {

   if (pressed) {
    //code to call array
     }
  }

我认为 bool 和 if 循环的简单组合就足够了,但这不起作用。我接近这个概念吗?需要进行哪些更改才能使其正常运行?

【问题讨论】:

  • 你只是在 Unity 中使用 INVOKE 做一个简单的计时器

标签: c# unity3d button pressed


【解决方案1】:

您可以采取一些措施来实现这一目标。您当前的代码永远不会切换 bool pressed。您可以像现在一样使用本地化的布尔值来捕获不需要的按钮按下,但可能有更好的方法。

我会考虑更改按钮的难处理性,以向最终用户展示他们无法在短时间内按下按钮。

using UnityEngine.UI;

// button that will be pressed
[SerializeField] private Button btn = null;

// time until the button is re-enabled after being pressed
private float timeToWait = 5f;

// reference to the coroutine that toggles our button
private Coroutine buttonDisabled = null;

private void Start()
{
    // you can either add the OnClick in the inspector, or you can programmatically add it here
    btn.onClick.AddListener(ClickButton);
}

public void ClickButton()
{
    // if we have an ongoing coroutine do not start another
    if(buttonDisabled != null)
        return;

    // start our coroutine to re-enable the button
    buttonDisabled = StartCoroutine(DisableButtonForSeconds(timeToWait));

    // put any other code needed here such as displaying a new quote
}

private IEnumerator DisableButtonForSeconds(float seconds)
{
    // disable the button 
    btn.interactable = false;

    // wait for our amount of time to re-enable
    yield return new WaitForSeconds(seconds);
    
    // re-enable the button
    btn.interactable = true;

    // reset our reference to be called again
    buttonDisabled = null;
}

将编辑器中的按钮分配给btn,并为timeToWait 设置您希望在按钮按下之间等待的时间。您还需要在代码或检查器中将按钮的OnClick 分配给ClickButton。使用此解决方案,将无法调用该函数,因为按钮本身将变灰且无法单击。 timeToWait 持续时间结束后,按钮将重新激活。将您需要的任何其他代码放入驱动您的报价循环的 ClickButton 方法中。

编辑:这是类似的代码,但根据要求使用Invoke 而不是Coroutine

using UnityEngine.UI;

// button that will be pressed
[SerializeField] private Button btn = null;

// time until the button is re-enabled after being pressed
private float timeToWait = 5f;

private void Start()
{
    // you can either add the OnClick in the inspector, or you can programmatically add it here
    btn.onClick.AddListener(ClickButton);
}

public void ClickButton()
{
    // do not start the function if we are already in the process
    if (IsInvoking("ReEnableButton"))
        return;

    // disable our button interactability
    btn.interactable = false;

    // call our function ReenableButton in timeToWait seconds
    Invoke("ReEnableButton", timeToWait);
}

private void ReEnableButton()
{
    // re-enable the button
    btn.interactable = true;
}

编辑 2:有几种方法可以让一个按钮禁用所有四个按钮。在一般实践中,您不希望这些按钮相互了解,因此最好创建一个按钮管理器来处理 OnClick 现在并将事件发送给它所知道的所有 Buttons

using UnityEngine.UI;

public class ButtonManager : MonoBehaviour
{
    // assign these button references in the inspector by dragging them into the list
    [SerializeField] private List<YourButtonScript> YourButtons = new List<YourButtonScript>();
    
    private void Start()
    {
        // assign the onClick of each button here INSTEAD of the Start() in the button class   
        // you can still have an onClick in the Button itself, but do NOT have it do the disabling
        
        foreach(YourButtonScript btn in YourButtons)
        {
            // assign our onClick to callback to disable all buttons 
            btn.SetDisableOnclick(DisableAllButtons);
        }
    }
    
    public void DisableAllButtons()
    {
        foreach(YourButtonScript btn in YourButtons)
            btn.DisableButton();
    }
}

public class YourButtonScript : MonoBehaviour
{
    using UnityEngine.UI;
        
    // button that will be pressed
    [SerializeField] private Button btn = null;
    
    // time until the button is re-enabled after being pressed
    private float timeToWait = 5f;
    
    // reference to the coroutine that toggles our button
    private Coroutine buttonDisabled = null;
    
    public delegate void DisableButtonCallback();
    
    public void SetDisableOnclick(DisableButtonCallback callback)
    {
        // add the callback to the manager
        btn.onClick.AddListener(delegate{callback();});
    }
    
    private void Start()
    {
        // do NOT call the ClickButton anymore from here as the manager handles it
        // if you have other button specific data put it in HandleSpecificButtonQuoteData() now
        btn.onClick.AddListener(HandleSpecificButtonQuoteData);
    }
    
    private void HandleSpecificButtonQuoteData()
    {
        // put whatever code here that is specific to JUST this button
        // if it handles the quotes or what not, display it here
    }
    
    public void DisableButton()
    {
        // if we have an ongoing coroutine do not start another
        if(buttonDisabled != null)
            return;
    
        // start our coroutine to re-enable the button
        buttonDisabled = StartCoroutine(DisableButtonForSeconds(timeToWait));
    }
    
    private IEnumerator DisableButtonForSeconds(float seconds)
    {
        // disable the button 
        btn.interactable = false;
    
        // wait for our amount of time to re-enable
        yield return new WaitForSeconds(seconds);
        
        // re-enable the button
        btn.interactable = true;
    
        // reset our reference to be called again
        buttonDisabled = null;
    }   
}

如果您对此有任何疑问,请告诉我。

【讨论】:

  • Clean - 我唯一建议的是将方法从 DisableButton 重命名为 EnableButtonAfterDelay,因为它更好地描述了协程正在做什么。
  • @Charleh 谢谢!注意到并更新。肯定会带来更多的清晰度。
  • 我实际上会将btn.interactable = false; 移动到例程中,而是将其称为DisableButtonForSeconds(float seconds) tbh:D
  • @derHugo 我更喜欢这样。更新了!
  • 感谢大家的帮助!
猜你喜欢
  • 1970-01-01
  • 2012-07-03
  • 1970-01-01
  • 2010-12-17
  • 1970-01-01
  • 1970-01-01
  • 2018-09-05
  • 1970-01-01
  • 2019-11-25
相关资源
最近更新 更多