Unity에서 특정 순서로 키를 입력했는지 여부를 결정합니다.

27757 단어 C#Unityunitasktech

개요


특정 순서로 키를 입력한 구조를 탐지해 봤다.
중간에 잘못되면 리셋되며 1부터 입력해야 합니다.
또한 첫 번째 문자를 입력한 후 일정 시간이 지나면 초기화하는 시간 초과 기능도 있다.
TypeChecker.cs
https://gist.github.com/nekomimi-daimao/1dece355acf66b84aaaaa185cff6e271

몸짓



입력하십시오nekomimi.5초 초과.
키 입력 자체는 표시되지 않았지만, 이렇게 입력했다.
  • nekomi k 및 입력

  • 입력ne 5초 대기
  • nekomimi 및 입력
  • 동작의 샘플 인코딩은 이런 느낌입니다.
    구조기의 매개 변수로 교부IProgress<(int numerator, int denominator)>를 중도에 거쳐 typeChecker.OnComplete에 등록된 활동.
    using System;
    using Cysharp.Threading.Tasks;
    using UnityEngine;
    using UnityEngine.UI;
    
    namespace Nekomimi.Daimao
    {
        public class TypeCheckerExample : MonoBehaviour, IProgress<(int numerator, int denominator)>
        {
            private static readonly KeyCode[] Command =
            {
                KeyCode.N,
                KeyCode.E,
                KeyCode.K,
                KeyCode.O,
                KeyCode.M,
                KeyCode.I,
                KeyCode.M,
                KeyCode.I,
            };
    
            [SerializeField]
            private Slider _slider = default;
    
            [SerializeField]
            private Text _textSlider = default;
    
            [SerializeField]
            private Text _textComplete = default;
    
            private void Start()
            {
                var typeChecker = new TypeChecker(Command, 5f, this, this.GetCancellationTokenOnDestroy());
                typeChecker.OnComplete += () =>
                {
                    _textComplete.text = "COMPLETE!";
                    Debug.Log("COMPLETE!");
                };
            }
    
            public void Report((int numerator, int denominator) value)
            {
                var (numerator, denominator) = value;
                _slider.maxValue = denominator;
                _slider.value = numerator;
                _textSlider.text = $"{numerator} / {denominator}";
    
                Debug.Log($"progress {numerator} / {denominator}");
            }
        }
    }
    
    그나저나 UniTask.v2그런데 특별히 새로운 기능이 없어서 v1도 갈 수 있어요.

    TypeChecker 컨텐트에 대한 설명


    CurrentPressed


    우선 가장 간단한 현재의 입력 키를 얻는 것부터 시작한다.
    유니티는 기준을 얻지 못해 현재 어떤 키API를 눌렀는지 스스로 만들어야 한다.[1]
    다소Enum의 배열이라고는 하지만 Update마다 포환을 돌리면 저항력이 강해 가장 적합한 해결 방안이다.InputSystem 새로워진 것 같은데 이 근처에서도 살 수 있을까요?Enum에서 None에 속하지 않는 기본값이 끊겼으면 좋겠습니다.예의입니다.
    /// <summary>
    /// <see cref="KeyCodeAlphabet"/>に含まれている現在押されているキーを返す.
    /// </summary>
    /// <returns><see cref="KeyCode"/></returns>
    private static KeyCode CurrentPressed()
    {
        if (!Input.anyKeyDown)
        {
            return KeyCode.None;
        }
        // every Update, no LINQ
        foreach (var keyCode in KeyCodeAlphabet)
        {
            if (Input.GetKeyDown(keyCode))
            {
                return keyCode;
            }
        }
        return KeyCode.None;
    }
    

    TypeCommandAsync


    이것은 정확한 키를 연속으로 입력했는지 확인하는 데 쓰이는 것이다.
    시간 초과 카운트다운을 시작하는 관계에 대해서는 첫 번째 자모만 이 방법 외에 판정된다.
    그리고 1부터KeyCode의 for 순환을 시작합니다. 키 입력이 있을 때 기대하면 for 순환을 계속하고 다른 키라면 for 순환을 중지합니다.
    즉 for 순환을 종료할 때 = 필요한 모든 키를 입력할 때다.
    for Loop에서 while Loop을 회전하는 것도 저한테는 촉감이 있지만 이것도 가장 적합한 해결 방법이라고 할 수 있겠죠...?
    사용goto은 피하지만 이런 다중순환을 사용할 수밖에 없는 상황에서goto는 오히려 이해하기 쉽다.근데 안 써봐서 싫어.
    /// <summary>
    /// キー入力を監視して正しく入力されたかを判定する.
    /// 最初の1文字は判定しない.
    /// </summary>
    /// <param name="progress"><see cref="IProgress{T}"/> (分子/分母)</param>
    /// <param name="token"><see cref="CancellationToken"/></param>
    /// <returns>true/false = 成功/失敗</returns>
    private async UniTask<bool> TypeCommandAsync(
        IProgress<(int numerator, int denominator)> progress, CancellationToken token)
    {
        for (var count = 1; count < Command.Length; count++)
        {
            while (true)
            {
                await UniTask.Yield();
                if (token.IsCancellationRequested)
                {
                    return false;
                }
                var current = CurrentPressed();
                if (current == KeyCode.None)
                {
                    // 何も入力していない場合は判定しない
                    continue;
                }
    
                if (Command[count] != current)
                {
                    // 違うキーが入力されたので中断する
                    return false;
                }
    
                // 求めているキーが入力されたので進捗を通知して次のキーに進む
                progress?.Report((count + 1, Command.Length));
                break;
            }
        }
        return !token.IsCancellationRequested;
    }
    

    CheckTypeLoop


    이것은 내가 이번에 가장 고민하는 곳이다.
  • 부터 첫 번째 문자 시간 초과 카운트다운
  • 기타 키 입력 등으로 입력이 중단되면 시간 초과도 복원
  • 이에 대한 대응책UniTask.WhenAny으로 단순한 시간 경과와 시간 초과 대상이 되는 처분 경쟁을 하고 시간 경과가 먼저 오면 처분을 멈추는 느낌.CancellationTokenSource 시간 초과 설정은 원래 이렇죠. 그런데 저는 아무렇게나 던지는 걸 싫어해요Exception[2]. 그래서 시간초과UniTask.WhenAny로 해결하기로 했어요.
    private async UniTaskVoid CheckTypeLoop(IProgress<(int numerator, int denominator)> progress, CancellationToken baseToken)
    {
        var first = Command[0];
    
        while (true)
        {
            await UniTask.Yield();
            if (baseToken.IsCancellationRequested)
            {
                return;
            }
            if (CurrentPressed() != first)
            {
                // 最初の1文字が入力されるまではタイムアウトも以後の判定も行わない
                progress?.Report((0, Command.Length));
                continue;
            }
    
            // 最初の1文字が入力された
            progress?.Report((1, Command.Length));
    
            var cancelSource = CancellationTokenSource.CreateLinkedTokenSource(baseToken);
            var token = cancelSource.Token;
    
            bool result;
            // 1文字目以降のキーが順番に入力されたら完了する
            var type = TypeCommandAsync(progress, token);
    
            if (TimeoutSecond > 0f)
            {
                // タイムアウトが設定されている場合はカウントする
                var timeout = UniTask.Delay(TimeSpan.FromSeconds(TimeoutSecond), cancellationToken: token);
                var (hasResultLeft, ret) = await UniTask.WhenAny(type, timeout);
                // キー入力のtaskが先に完了してかつそれがtrue
                result = hasResultLeft && ret;
            }
            else
            {
                // タイムアウトを待たない場合はキー入力の結果だけを待つ
                result = await type;
            }
    
            if (result)
            {
                OnComplete?.Invoke();
            }
    
            if (!cancelSource.IsCancellationRequested)
            {
                cancelSource.Cancel();
            }
        }
    }
    

    호출 시스템 같은 거.


    나도 분명히 구조기의 매개 변수에서 IProgress를 얻으면 완성된다고 생각하지 않는다Action OnComplete 이후에 등록하는 것이 어떻고 어느 것으로 통일되겠는가. 그러나 대부분 용례에서 완성하면 된다. 구조기의 매개 변수가 너무 많아서 매일 따뜻하다.
    그나저나 IProgress에서도 움직인다.

    총결산


    디버그 기능을 몰래 시작하는 데 사용되는 숨겨진 명령 제조사입니다.null방법주위밖에아무것도 안보고했는데,이건타자게임같은코드참고해야하는거 아닌가...?하고 생각해 보니까
    "강아지가 쓴 건가?"💕」이런 코드에 계속 탔는데 요즘'기다리고 있나...?'이런 마음이지만 자신이 생각하는 예쁜 코드를 적으면'정의'를 되찾을 수 있다.이것은 메인 요리다.
    그렇긴 한데 한 1~2주 정도 지났어요.💕」이렇게 말하면서 자신의 전선에 토마토를 넣었죠.진보는 이렇다.
    끝.
    각주
    여자, 농담이야... ↩︎
    시간 초과와 취소는 똑같다Input,투척된 C# 언어 규격은 도대체 어떻게 생각하는가...?↩︎

    좋은 웹페이지 즐겨찾기