简体   繁体   English

如何让 for 循环仅在玩家每次按下 Z 时循环

[英]How do I get the for loop to only loop every time the player presses Z

I am trying to cycle through a list of dialogue to update a text component.我正在尝试循环浏览对话列表以更新文本组件。

The var i is only supposed to increases when the player presses z but every time I try the var i increases to the max value instead of once every time I press Z. var i应该只在玩家按下 z 时增加,但每次我尝试 var i增加到最大值而不是每次我按下 Z 时增加一次。

IEnumerator gameDialog ( )
{
    while ( i < prologueDialog.Count )
    {
        PlayerPrefs.SetInt ( "StoryProgress(Prologue)", i );
        currentListIndex = PlayerPrefs.GetInt ( "StoryProgress(Prologue)" );

        if ( i == 0 )
        {
            dialogText.text = prologueDialog [ 0 ];
        }

        if ( Input.GetKey ( KeyCode.Z ) )
        {
            pressedZ = true;
            dialogText.text = "";
            dialogText.text = prologueDialog [ i ];
        }

        yield return new WaitUntil ( ( ) => pressedZ );
        pressedZ = false;
        oldi = i;
        i++;
        if ( oldi + 1 != i )
        {
            i = oldi + 1;
        }
        Debug.Log ( i );
    }
}

I've tried everything I could think of using yield , WaitUntil , WaitForSeconds , bool values to stop the if statement from running more than once.我已经尝试了所有我能想到的使用yieldWaitUntilWaitForSecondsbool值来阻止 if 语句多次运行的方法。

Input.GetKey will return true while the key is held down . Input.GetKey在按住该键时返回 true。 What you're after is likely Input.GetKeyDown which returns true during the frame it's initially pressed, and will not return true until the same key has been released.您所追求的可能是Input.GetKeyDown ,它在最初按下的帧中返回 true,并且在释放相同的键之前不会返回 true。

The WaitUntil IEnumerator causes the code execution to pause at that spot, until the function predicate returns true. WaitUntil IEnumerator导致代码执行在该点暂停,直到函数谓词返回 true。 What that means in layman's terms is that the code is going to stop on that line, and move no further, until pressedZ somehow becomes true.用外行的话来说,这意味着代码将停在那条线上,不再移动,直到pressedZ以某种方式变为真。 But, given that the code won't progress, you can start to see that the keys aren't ever read again, and therefore, pressedZ will never become true.但是,鉴于代码不会继续,您可以开始看到键不再被读取,因此pressedZ永远不会变为真。

One thing to note is that saving any game state to the PlayerPrefs is almost universally frowned upon.需要注意的一件事是,将任何游戏状态保存到PlayerPrefs几乎是普遍不赞成的做法。 But that's another issue that can be resolved after getting your dialogue running.但这是另一个可以在对话运行后解决的问题。

Instead of trying to poll your keyboard input in a "coroutine", might I suggest you use the already available Update method to use as your frame based polling mechanism?我建议您使用已经可用的Update方法作为基于框架的轮询机制,而不是尝试在“协程”中轮询您的键盘输入? It also still includes the PlayerPrefs persistence, which I would suggest replacing at your earliest convenience.它还包括PlayerPrefs持久性,我建议您尽早更换。 This has been written, but not tested.这已被写入,但未经测试。

public class Test : MonoBehaviour
{
    [SerializeField] private TextMeshPro dialogText;

    private List<string> _dialoguePhrases = null;
    private string _storyName;
    private int _dialogueIndex = 0;

    private void Awake ( )
    {
        HideDialogue ( );
    }

    public void ShowDialogue ( List<string> dialoguePhrases, string storyName = "StoryProgress(Prologue)" )
    {
        _dialogueIndex = PlayerPrefs.GetInt ( storyName, 0 );

        // check the saved progress index with the newly passed in dialoguePhrases (or -1 if null).
        if ( _dialogueIndex >= ( dialoguePhrases?.Count ?? -1 ) )
        {
            HideDialogue ( );
            return;
        }

        _dialoguePhrases = dialoguePhrases;
        _storyName = storyName;
        dialogText.text = dialoguePhrases [ _dialogueIndex ];
        enabled = true; // Lets the Update method run.
    }

    public void HideDialogue ( )
    {
        _dialoguePhrases = null;
        _dialogueIndex = 0;
        dialogText.text = string.Empty;
        enabled = false; // Stops the Update method from being called.
    }

    private void Update ( )
    {
        if ( Input.GetKeyDown ( KeyCode.Z ) && _dialoguePhrases != null )
        {
            if ( ++_dialogueIndex < _dialoguePhrases.Count )
            {
                dialogText.text = _dialoguePhrases [ _dialogueIndex ];
                PlayerPrefs.SetInt ( "StoryProgress(Prologue)", _dialogueIndex );
            }
            else
            {
                // You've clicked on the last one, and now you need to do something after the dialogue has finished.
                HideDialogue ( );
            }
        }
    }
}

The idea here is that you send through a list of dialogue phrases, and a name (id) of where the dialogue state would be persisted (preferably not in the PlayerPrefs).这里的想法是你发送一个对话短语列表,以及一个对话状态将被持久化的名称(id)(最好不在 PlayerPrefs 中)。

The Update method is then enabled, when the component itself has it's enable flag set to true.当组件本身将其enable标志设置为 true 时,将启用Update方法。 The normal checks are made in Update , and when the end of the dialogue is reached, the component turns itself off waiting for the next show dialogue command.正常检查在Update中进行,当对话结束时,组件将自行关闭,等待下一个显示对话命令。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM