728x90
반응형

개요

기존 Unity Input System을 사용하기엔 너무 다양한 것들을 요구하기에 그냥 새로 구상

 

조건

- MLB Press (X); 마우스 왼쪽 클릭

- MRB Press (Y); 마우스 오른쪽 클릭

- Combine WASD (WASD+); 조합키

- Hold (~); 키 홀드

- Repeat (+); 키 반복입력

- Delay (_); 입력 없음, 이후 재입력 가능

- Check Button Release; 버튼 떼기 확인

- Input Stream; Input 저장

- Reset Inputs; 일정 시간 이후 Input Stream 초기화

- Check Available Command; Input Stream이 사용가능한지 확인

================================

이후 String 비교 방식이 아닌 Command Tree을 이용하여 다시 구현할 예정

 

InputManager

Variable

private

  • bool grounded
    현재 지상에 있는지 공중에 있는지 저장하는 테스트 변수
  • List<string> g_commandList
    지상에서 사용가능한 command 목록
  • List<string> a_commandList
    공중에서 사용가능한 command 목록
  • string inputStream
    Input을 저장하는 Stream
  • string rawInput
    MLB, MRB 입력을 저장
  • string combineKey
    WASD 입력을 저장
  • string complexInput
    hold, repeat를 저장
  • string currentInput
    rawInput, combineInput, complexInput이 조합되어 나오는 현재 입력
  • float resetTime
    InputStream이 초기화되는 최소 시간
  • float resetTimer
    InputStream 초기화를 위한 내부변수
  • float holdTime
    hold로 판단되는 최소 시간
  • float holdTimer
    hold 판단을 위한 내부변수
  • float delayTime
    delay로 판단되는 최소 시간
  • float delayTimer
    delay 판단을 위한 내부변수
  • float repeatTime
    repeat으로 판단되는 최소 반복 주기
  • float clickTime
    현재 시간과 클릭한 시간을 비교하여 repeatTime과 비교하여 repeat를 판단하는 내부변수
  • bool pressed
    rawInput이 들어온 순간 true가 되는 클릭 확인용 변수
  • bool released
    rawInput이 끝나는 순간 true가 되는 떼기 확인용 변수
  • bool holding
    hold하고 있는 동안 true가 되는 내부변수
  • bool held
    hold로 판단되면 Reset 전까지 true가 되는 확인용 변수
  • bool repeating
    repeat하고 있는 동안 true가 되는 내부변수
  • bool repeated
    repeat으로 판단되면 Reset 전까지 true가 되는 확인용 변수
  • bool delaying
    delay동안 Reset true가 되는 내부변수
  • bool delayed
    delay로 판단되면 Reset 전까지 true가 되는 확인용 변수

Method

private

  • void ResetInputs()
    =Input과 관련된 것을 모두 초기화하는 함수
    [ResetPrevInputs()]
    holding, delaying, repeating를 false로 초기화
    rawInput과 combineKey를 ""로 초기화
  • void ResetPrevInputs()
    =확인용 변수들을 초기화하는 함수
    pressed, released 등 확인용 변수 초기화
  • void RestTimers()
    =Timer들을 초기화하는 함수
    resetTimer, holdTimer, delayTimer를 0으로 초기화
  • void ResetStream()
    =inputStream을 초기화하는 함수
  • void CheckReset()
    =inputStream 초기화 여부를 판단하는 함수
    holding이 true인 경우 resetTimer는 0으로 고정
    delayed 이후 resetTimer가 동작하며 resetTimer가 resetTime을 넘어가면 resetTimer를 0으로 초기화
    [ResetInputs]
    [ResetTimers]
    [ResetStream]
  • void CheckInput()
    =Input을 처리하는 모든 함수를 한번에 호출하는 함수
    [CheckCombineKey()]; WASD 입력 처리
    [CheckRawInput(1)]; 마우스 오른쪽 클릭 처리
    [CheckRawInput(0)]; 마우스 왼쪽 클릭 처리
    [CheckComplexInput()]; 홀드, 반복 입력 처리
    [CheckInputDelay()]; 입력 없음 처리
    [UpdateCurrentInput()]; currentInput 갱신
  • void CheckCombineKey()
    =WASD 입력을 처리하는 함수
  • void CheckRawInput(int button)
    =마우스 입력을 처리하는 함수
    MLB 입력일 경우 combineKey를 ""로 초기화한다.
    1. MouseButtonDown이 되면 rawInput에 정보를 저장하고 확인용변수들을 설정
        [CheckRepeat]
        [ResetTimers]
        [AddToStream(rawInput)]
    2. MouseButton이 되면 pressed를 false로 설정
        holdTimer로 hold를 판단
    3. MouseButtonUp이 되면
        holding을 false로 설정
        released를 true로 설정
  • void CheckInputDelay()
    =입력 없음을 판단하는 함수
    released 이후 delayTimer가 동작
    delayTimer가 delayTime을 넘어가면 delaying,delayed를 true로 설정하고 rawInput을 ""로 초기화
    [AddDelayToStream()]
  • void CheckRepeat()
    =반복 입력을 판단하는 함수
    현재 시간과 마지막으로 클릭한 시간을 비교하여 repeatTime보다 작다면 반복입력으로 판단
    repeating, repeated를 true로 설정
  • void CheckComplexInput()
    =홀드와 반복입력을 처리하는 함수
    1. holding일 때 complexInput을 "~"로 설정하고 InputStream에 추가
        [AddHoldToStream()]
    2. repeating이고 delaying이 아닐때 complexInput을 "+"로 설정하고 InputStream에 추가
        [AddRepeatToStream()]
    3. 아닐 때 complexInput을 ""로 초기화하고 holding, repeating을 false로 설정
  • void UpdateCurrentInput()
    =combineKey, complexInput, rawInput을 조합하여 currentInput을 갱신
  • void AddToStream(string input)
    =입력을 inputStream에 추가하는 함수
    repeating이 false일 때 combineKey 여부에 따라 inputStream에 추가
    이후 사용가능한 command인지 확인
    [CheckAvailableCommand()]
  • void AddHoldToStream()
    =Hold를 inputStream에 추가하는 함수
    중복 추가와 repeat과의 충돌을 방지
  • void AddRepeatToStream()
    =Repeat를 inputStream에 추가하는 함수
    중복 추가와 hold와의 충돌을 방지
  • void AddDelayToStream()
    =Delay를 inputStream에 추가하는 함수
    중복 추가 방지
  • void CheckAvailableCommand()
    =현재 inputStream에 추가된 command가 사용가능한지 확인하는 함수
    inputStream이 null인 경우 return
    지상에 있는지에 따라 [CheckAvailableFromList()]를 호출
  • void CheckAvailableFromList(List<string> list)
    =list로부터 inputStream이 사용가능한 command인지 판단하는 함수
    inputStream으로 시작하는 command가 있다면 사용가능으로 판단
    아니라면 inputStream에 rawInput를 추가
    [ResetInputs]

 

전체 코드

더보기
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using Unity.VisualScripting.Antlr3.Runtime;
using UnityEngine;

public class InputTest : MonoBehaviour
{
    [Header("For Test")]
    [SerializeField] private bool grounded = true;

    [Space(20)]
    [SerializeField] private List<string> g_commandList = new List<string>();
    [SerializeField] private List<string> a_commandList = new List<string>();

    [Space(20)]
    [SerializeField] private string inputStream;

    [Space(20)]
    [SerializeField] private string rawInput;
    [SerializeField] private string combineKey;
    [SerializeField] private string complexInput;
    [SerializeField] private string currentInput;

    [SerializeField] private float resetTime;
    private float resetTimer;
    [SerializeField] private float holdTime;
    private float holdTimer;
    [SerializeField] private float delayTime;
    private float delayTimer;
    [SerializeField] private float repeatTime;
    private float clickTime;

    [SerializeField] private bool pressed;
    [SerializeField] private bool released;

    [SerializeField] private bool holding;
    private bool held;
    [SerializeField] private bool repeating;
    private bool repeated;
    [SerializeField] private bool delaying;
    private bool delayed;

    private void Awake()
    {
        ResetStream();
        ResetInputs();
        ResetTimers();
        clickTime = -1.0f;
    }

    void Update()
    {
        CheckInput();
        CheckReset();

        //DebugInputs();
    }

    private void DebugInputs()
    {
        if(pressed)
        {
            Debug.Log("Press");
        }
        if(holding)
        {
            Debug.Log("Hold");
        }
        if(released)
        {
            Debug.Log("Release");
        }
        if(delaying)
        {
            Debug.Log("delay");
        }
        if(repeating)
        {
            Debug.Log("Repeat");
        }
    }

    private void CheckInput()
    {
        CheckCombineKey();
        CheckRawInput(1);
        CheckRawInput(0);
        CheckComplexInput();
        CheckInputDelay();

        UpdateCurrentInput();
    }
    private void UpdateCurrentInput()
    {
        if(combineKey != "")
        {
            currentInput = combineKey + "+" + rawInput + complexInput;
        }
        else
        {
            currentInput = rawInput + complexInput;
        }
    }

    private void CheckRawInput(int button)
    {
        if(button == 0)
        {
            combineKey = "";
        }
        if(Input.GetMouseButtonDown(button))
        { 
            rawInput = (button==0) ? "X" : "Y";

            pressed = true;
            holding = false;
            released = false;
            CheckRepeat();
            ResetTimers();

            AddToStream(rawInput);
        }
        else if(Input.GetMouseButton(button))
        {
            pressed = false;
            holdTimer += Time.deltaTime;
            if(holdTimer > holdTime)
            {
                holding = true;
                held = true;
            }
            //release = false;
        }
        else if(Input.GetMouseButtonUp(button))
        {
            //press = false;
            holding = false;
            released = true;
        }
    }

    private void CheckInputDelay()
    {
        if(released == true)
        {
            delayTimer += Time.deltaTime;
            if(delayTimer >= delayTime)
            {
                delaying = true;
                delayed = true;
                rawInput = "";
                AddDelayToStream();
            }
            else
            {
                delaying = false;
                //repeat = false;
            }
        }
    }
    private void CheckRepeat()
    {
        if((Time.time - clickTime) < repeatTime)
        {
            repeating = true;
            repeated = true;
        }
        else
        {
            clickTime = Time.time;
        }
    }

    private void CheckCombineKey()
    {
        if(Input.GetKey(KeyCode.W))
        {
            combineKey = "W";
        }
        else if(Input.GetKey(KeyCode.S))
        {
            combineKey = "S";
        }
        else if(Input.GetKey(KeyCode.A))
        {
            combineKey = "A";
        }
        else if(Input.GetKey(KeyCode.D))
        {
            combineKey = "D";
        }
        else
        {
            combineKey = "";
        }
    }

    private void CheckComplexInput()
    {
        if(holding)
        {
            complexInput = "~";
            AddHoldToStream();
        }
        else if(repeating && !delaying)
        {
            complexInput = "+";
            AddRepeatToStream();
        }
        else
        {
            complexInput = "";
            holding = false;
            repeating = false;
        }
    }
    private void CheckReset()
    {
        if(holding == true)
        {
            resetTimer = 0;
            return;
        }

        if(delayed == true)
        {
            resetTimer += Time.deltaTime;
            if(resetTimer > resetTime)
            {
                resetTimer = 0;
                ResetInputs();
                ResetTimers();
                ResetStream();
            }
        }
    }
    private void ResetInputs()
    {
        Debug.Log("Reset");
        ResetPrevInputs();
        holding = false;
        delaying = false;
        repeating = false;
        rawInput = "";
        combineKey = "";
    }
    private void ResetPrevInputs()
    {
        pressed = false;
        released = false;
        held = false;
        delayed = false;
        repeated = false;
    }
    private void ResetTimers()
    {
        resetTimer = 0;
        holdTimer = 0;
        delayTimer = 0;
    }

    private void ResetStream()
    {
        inputStream = "";
    }

    private void AddToStream(string input)
    {
        if (repeating == false)
        {
            if(combineKey == "")
            {
                inputStream += input;
            }
            else
            {
                Debug.Log("CombineKey");
                inputStream += combineKey + "+" + input;
            }

        }
        CheckAvailableCommand();
    }
    private void AddHoldToStream()
    {
        if (inputStream.EndsWith("~"))
        {
            return;
        }
        repeating = false;
        inputStream += "~";

        CheckAvailableCommand();
    }
    private void AddRepeatToStream()
    {
        if (inputStream.EndsWith("+"))
        {
            return;
        }
        holding = false;
        inputStream += "+";

        CheckAvailableCommand();
    }
    private void AddDelayToStream()
    {
        if (inputStream.EndsWith("_"))
        {
            return;
        }
        inputStream += "_";

        CheckAvailableCommand();
    }

    private void CheckAvailableCommand()
    {
        if(string.IsNullOrEmpty(inputStream))
        {
            return;
        }
        if(grounded)
        {
            CheckAvailableFromList(g_commandList);
        }
        else
        {
            CheckAvailableFromList(a_commandList);
        }

    }

    private void CheckAvailableFromList(List<string> list)
    {
        for(int i = 0; i < list.Count; i++)
        {
            if (list[i].StartsWith(inputStream))
            {
                //Debug.Log("Available: [" + g_commandList[i] + "=" + inputStream + "]");
                Debug.Log("Available");
                return;
            }
            else
            {
                //Debug.Log("Unavailable input");
                //Debug.Log("Not Available: [" + inputStream + "]");
            }
        }
        inputStream = rawInput;
        ResetInputs();
    }
}