Кнопка Unity UI удерживает двойной щелчок, как я могу обойти это? - PullRequest
0 голосов
/ 05 ноября 2019

У меня есть две кнопки, настроенные в интерактивной фантастической игре, каждое нажатие вызывает новую строку текста. Проблема в том, что каждый раз, когда я нажимаю на кнопку, я получаю два зарегистрированных отладочных сообщения, информирующих меня о щелчке, и моя игра перемещает два раздела текста.

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

Вот мой текущий код:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class AdventureGame : MonoBehaviour
{
    [SerializeField]
    private Text _textComponent;
    [SerializeField]
    private State _startingState;

    private State state;

    [SerializeField]
    private Button _input0Button;
    [SerializeField]
    private Button _input1Button;

    [SerializeField]
    private Text _choices1;
    [SerializeField]
    private Text _choices2;

    private bool _buttonOnePressed;
    private bool _buttonTwoPressed;

    void Start()
    {
        state = _startingState;
        _textComponent.text = state.GetStateStory();
        _input0Button.onClick.AddListener(Input0Button);
        _input1Button.onClick.AddListener(Input1Button);
        _buttonOnePressed = false;
        _buttonTwoPressed = false;


    }
    void Update()
    {
        ManageState();
    }
    private void ManageState()
    {
        if (state._choice == true)
        {
            _choices1.text = state.GetChoiceOne();
            _choices2.text = state.GetChoiceTwo();
            _textComponent.text = state.GetStateStory();
            _input0Button.gameObject.SetActive(true);
            _input1Button.gameObject.SetActive(true);
            if(_buttonOnePressed == true)
            {
                StartCoroutine(WaitForItOne());
            }
            else if(_buttonTwoPressed == true)
            {
                StartCoroutine(WaitForItTwo());
            }
        }
        else if (state._choice == false)
        {
            _choices1.text = state.GetChoiceOne();
            _choices2.text = state.GetChoiceTwo();
            _textComponent.text = state.GetStateStory();
            _input0Button.gameObject.SetActive(true);
            _input1Button.gameObject.SetActive(false);
            if(_buttonOnePressed == true)
            {
                StartCoroutine(WaitForItOne());
            }
        }

    }
    private void ManageChoiceOne()
    {
            _buttonOnePressed = false;
            State[] _newState = state.GetNextStatesArray();
            state = _newState[0];
    }
    private void ManageChoiceTwo()
    {
            _buttonTwoPressed = false;
            State[] _newState = state.GetNextStatesArray();
            state = _newState[1];
    }

    public void Input0Button()
    {
        Debug.Log("Input 0 pressed");
        _buttonOnePressed = true;
    }
    public void Input1Button()
    {
        Debug.Log("Input 1 pressed");
        _buttonTwoPressed = true;
    }
    IEnumerator WaitForItOne()
    {
        yield return new WaitForSeconds(3.0f);
        ManageChoiceOne();
    }
    IEnumerator WaitForItTwo()
    {
        yield return new WaitForSeconds(3.0f);
        ManageChoiceTwo();
    }

}

1 Ответ

2 голосов
/ 05 ноября 2019
  • Прежде всего вы продолжаете запускать новые сопрограммы в каждом кадре, например, _buttonOnePressed == true .. вы ждете 3 секунды, прежде чем окончательно снимите этот флаг!

  • Затем для двойного вызова убедитесь, что обратные вызовы не настроены также в Инспекторе! Похоже, что вы один раз добавили их в Инспектор и дополнительно добавили их в свой метод Start, чтобы они назывались дважды !

    Обратите внимание, что вы не увидите обратных вызовов, добавленных во время выполненияв инспекторе!

  • Почему вы вообще здесь используете Update? Весьма избыточно опрашивать состояние и значения bool и постоянно проверять и обрабатывать их состояния в каждом кадре. Я предпочел бы просто запустить подпрограмму в самом методе button, а вместо этого управлять целым событием кода!

  • (опционально). Чтобы дать пользователю лучшую обратную связь, я бы дополнительно в это время3 секунды делают кнопки не взаимодействующими .. оставляйте их активными, но не нажимаемыми:

// Remove state;
// Remove _buttonOnePressed
// Remove _buttonTwoPressed

private void Start()
{
    // Either remove this two lines or the callbacks set in the Inspector
    _input0Button.onClick.AddListener(Input0Button);
    _input1Button.onClick.AddListener(Input1Button);

    ManageState(_startingState);
}

// Remove Update

// This will be called only when actually needed
// since the state is passed in as parameter you don't need the private field
private void ManageState(State state)
{
    // These happen in both cases anyway
    _choices1.text = state.GetChoiceOne();
    _choices2.text = state.GetChoiceTwo();
    _textComponent.text = state.GetStateStory();
    _input0Button.gameObject.SetActive(true);

    // Here directly use the state flag
    // since the button is disabled when needed
    // there is no need for having different "states"
    // since anyway only the according button(s) is(are) available
    _input1Button.gameObject.SetActive(state._choice);
}

// (optional) Flag for avoiding concurrent routines
// Should be impossible since buttons get disabled but you never know
private bool alreadyHandlingButton;

private IEnumerator ManageChoice(bool isButtonOne)
{
    // (optional) Skip if another routine running
    if(alreadyHandlingButton) yield break;

    // (optional) Block other routines just in cade
    alreadyHandlingButton = true;

    // Disable interactions
    _input0Button.interactable = false;
    _input1Button.interactable = false;

    // This is the same for both buttons
    yield return new WaitForSeconds(3f);

    State[] _newState = state.GetNextStatesArray();

    var state = _newState[isButtonOne ? 0 : 1];

    // Only call ManageState when the state is actually changing
    ManageState(state);

    // (optional) Allow a new routine
    alreadyHandlingButton = false;

    // Enable interactions
    _input0Button.interactable = true;
    _input1Button.interactable = true;
}

public void Input0Button()
{
    // (optional) Ignore if other button is already handled
    if(alreadyHandlingButton) return;

    Debug.Log("Input 0 pressed");
    StartCoroutine(ManageChoice(true));
}

public void Input1Button()
{
    // (optional) Ignore if other button is already handled
    if(alreadyHandlingButton) return;

    Debug.Log("Input 1 pressed");
    StartCoroutine(ManageChoice(false));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...