입력
개요
격투 게임에서 입력은 플레이어 간의 빠른 전송, 정밀도 및 상태 입력 스트림을 단순히 소비하는 것이 아니라 일정 기간 동안 추적할 수 있는 능력을 필요로 합니다.
이 페이지에서는 유니티에서 캡처하는 플레이어 입력과 이러한 값이 Quantum에서 평가 및 계산되는 방법에 대해 설명합니다.
입력 구조체
대역폭을 낮게 유지하려면 일반적으로 입력 구조체를 가능한 작게 유지하는 것이 좋습니다. 이것은 입력의 일부로 단일 열거형 InputFlag
를 보유하여 Fighting Template에서 극단으로 밀어 넣습니다.
chsarp
input {
InputFlag inputFlag;
}
InputFlag
열거형 정의는 두 값의 거듭제곱을 명시적으로 할당하므로 비트 연산을 사용하여 InputFlag
를 조작할 수 있습니다. 이렇게 하면 InputFlag
가 여러 입력 값을 동시에 저장할 수 있습니다.
C#
// Input flags used to represent the directional and button inputs
enum InputFlag {
NONE = 0,
Left = 1,
Right = 2,
Down = 4,
Up = 8,
LP = 16, // light punch
LK = 32, // light kick
HP = 64, // heavy punch
HK = 128, // heavy kick
Directions = 15, // Used by the systems to extract the input directions from the input struct
Buttons = 240, // Used by the systems to extract the button input from the input struct
}
유니티 측
Fighting template은 모바일(UI 버튼)과 PC(키보드 및 게임 패드)의 두 가지 입력 인터페이스를 구현합니다. 빌드의 실행 플랫폼에 따라 실행 중인 한 입력 또는 다른 입력이 고려됩니다.
입력 인터페이스가 다양하더라도 입력 로직은 기기 간에 동일하게 유지됩니다.
입력 로직
입력 로직은 QuantumDemoInput.cs
스크립트에서 설정되며 PollInput
콜백을 리슨합니다.
키보드 입력
QuantumDemoInput.cs
의 KeycodeSet
구조체에 설정된 각 버튼은 부울 값으로 표시됩니다. 부울 값이 true로 평가되면 Input 구조체의 InputFlag
매개 변수로 유지되는 값이 그에 따라 업데이트됩니다.
C#
if (UInput.GetKey(Left)){
input.inputFlag |= InputFlag.Left;
}
모바일 입력
모바일 입력은 버튼의 누름 값을 처리하는 MobileJoystick
이라는 UI 스크립트와 모든 활동 MobileJoystick
스크립트와 입력이 들어왔을 때를 다루는 QuantumDemoInput.cs
로직의 두 부분으로 나뉘어 있습니다.
MobileJoystick
은 8개 방향으로 모두 이동할 수 있도록 2개의 플래그 매개변수를 제공합니다. 오른쪽 위 대각선은 Quantum.InputFlag.Up
과 Quantum.InputFlag.Right
으로 표시됩니다. flag1
과 flag2
가 동일한 값으로 설정되어 있으면 고유 입력으로 간주됩니다. 비트 방향 작업을 사용하면 각 UI 버튼의 설정에 관계없이 값 할당이 동일하게 유지됩니다.
C#
public class MobileJoystick : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler{
public Quantum.InputFlag flag1;
public Quantum.InputFlag flag2;
public Quantum.InputFlag FlagValue { get; private set; }
public void OnPointerEnter(PointerEventData eventData){
FlagValue = flag1 | flag2;
}
public void OnPointerExit(PointerEventData eventData){
FlagValue = Quantum.InputFlag.NONE;
}
}
QuantumDemoInput
은 알려진 MobileJoystick
스크립트 배열 위에서 반복되고 비트 또는 각 버튼에 있는 값을 함께 추가하는 데 사용됩니다.
C#
for (int i = 0; i < mobileButtons.Length; i++){
input.inputFlag |= mobileButtons[i].FlagValue;
}
Quantum 측
시뮬레이션 측(Quantum)에서는 여러 프레임에 걸친 순차 입력에 의해 트리거되는 조합과 지속적인 버튼 누름이 필요한 충전 공격을 모두 허용하려면 입력을 여러 프레임에 걸쳐 추적해야 합니다.
입력 시퀀스는 InputCommandData
에셋을 사용하여 편집 시 정의되고 InputBuffer
컴포넌트를 사용하여 런타임에 추적됩니다.
InputCommandData
InputCommandDataBase
는 추상 에셋 클래스입니다. 이 클래스는 필요에 맞게 TestCmdPair()
를 구현할 구체적인 에셋을 정의하는 데 사용됩니다.
C#
public abstract unsafe partial class InputCommandDataBase{
/// The parameter set for the forward and backward version of the input. Should be a fixed point parameter.
public CAParameters forDirectionParameter;
public CAParameters backDirectionParameter;
/// The forward and backward version of the command
public InputFlag[] forDirectionInputSequence;
public InputFlag[] backDirectionInputSequence;
public void TestCmdPair(Frame f, InputBuffer* i, int side, CustomAnimator* a, ref QList<InputValue> dSeq);
protected abstract bool TestCmd(Frame f, InputBuffer* iB, int side, InputFlag[] flagArray, ref QList<InputValue> directionalSequence);
}
Fighting Template에 포함된 구체적인 구현은 다음과 같습니다.
InputCommandData
그리고ChargeInputCommandData
.
InputCommandData
는 일련의 입력을 수행하여 플레이어가 트리거 하는 특수 동작을 활성화하는 데 사용됩니다. ChargeInputCommandData
는 동일한 입력을 유지하여 여러 프레임에 걸쳐 충전이 필요한 입력 시퀀스를 정의하는 데 사용됩니다.
InputBuffer
프레임의 일부로 각 플레이어별로 입력을 추적해야 합니다. 이를 위한 가장 편리하고 유연한 방법은 각 플레이어가 통제하는 엔티티의 컴포넌트를 이 목적에 전용으로 사용하는 것입니다(Fighting Template에서 사용하는 접근 방식).
InputBuffer
컴포넌트는 다음 세 가지를 추적하는 데 사용됩니다.
- 입력 방향
- 버튼 누름 그리고
- 입력의 누름 또는 뗀 시간의 길이
InputBuffer
는 InputBufferSystem
에 의해 업데이트됩니다.
C#
component InputBuffer{
list<InputValue> directionalSequence;
list<InputValue> buttonSequence;
array<InputTimer>[8] inputTimers;
}
InputValue
유형은 DSL에 정의된 단순한 구조체입니다. 이 파일에는 InputFlag
의 복사본과 연결된 프레임 번호가 포함되어 있습니다. 방향 입력 및 동작 버튼 시퀀스는 별도로 조작되므로 InputBuffer
컴포넌트에서 두 개의 InputValue
목록을 유지함으로써 별도로 추적됩니다.
C#
struct InputValue{
InputFlag inputFlag;
Int32 frame;
}
특정 입력이 눌리거나 해제된 시간은 InputTimer
구조체를 사용하여 추적됩니다.
C#
struct InputTimer{
FP timeDown;
FP timeUp;
}
InputBufferSystem
InputBufferSystem
은 두 가지의 목적이 있습니다:
- 입력 구조체에서 현재
InputFlag
를 검토하고 InputBuffer
컴포넌트를 업데이트합니다.
현재 입력의 입력 플래그를 평가하기 전에 방향 및 버튼 입력이 분리됩니다.
C#
InputFlag dirFlag = input->inputFlag & ~(InputFlag.Buttons);
InputFlag btnFlag = input->inputFlag & ~(InputFlag.Directions);
이 분할은 이동 세트를 트리거하기 위해 플레이어가 수행한 작업을 추적하는 데 도움이 됩니다. 먼저 UpdateInput()
은 입력이 보류 중인지 확인하여 InputBuffer
컴포넌트의 InputTimer
를 업데이트합니다.
- 눌려짐:해당 입력에 대한
InputTimer.TimeDown
이 증가 - 누르지 않음: 해당 프레임 동안 입력이 눌려 있지 않고 입력에 대한 재설정 허용 오차가 초과된 경우 해당 입력의
InputTimer.TimeDown
이 재설정됩니다. 이 작업은 충전 이동을 활성화하기 위해 수행됩니다(예: 몇 프레임에 대해 충전한 다음 앞으로 누름 및 버튼을 누름)
모든 InputTimers
가 업데이트된 후 InputBufferSystem
은 CustomAnimator
의 매개 변수를 이 새로운 값들로 업데이트합니다.
마지막 단계인 InputBufferSystem
은 InputBufferComponent
가 보유한 입력 시퀀스 목록을 추출합니다. 현재 입력의 방향값은 컴포넌트에 저장된 이전 InputValues
와 비교하여 확인되고 두 값이 다를 경우 업데이트됩니다. 이 목록은 각 플레이어의 파이터와 관련된 모든 InputCommandData
에셋에서 TestCmdPair()
메소드에 대한 매개 변수로 전달됩니다.
이 구현은 앞서 언급한 측면을 결합하여 플레이어들이 변경 사항 사이의 허용 오차(기본적으로 약 10프레임)와 함께 입력 시퀀스를 입력할 수 있도록 합니다.
예를 들어 플레이어의 파이터가 InputCmd_QuarterCircle
에셋을 보유하고 있는 경우, 입력 시퀀스가 다음 값으로 구성된 경우 QCF_F
애니메이션 매개 변수를 트리거하고 관련 동작을 실행합니다.
C#
{frame = 80, value = 4} // Down
{frame = 90, value = 6} // Down + Right
{frame = 100, value = 2} // Right
그런 다음 명령 버퍼가 32개 입력이므로 양수의 입력 시퀀스로 등록됩니다.
특별한 이동 트리거
유니티 애니메이터에서 편집 시 특별한 이동이 설정되고 CustomAnimatorGraph
에셋으로 베이크됩니다. 런타임의 InputBufferSystem
은 단순히 CustomAnimator
컴포넌트의 매개 변수를 업데이트합니다.
CustomAnimatorUpdater
가 CustomAnimator
컴포넌트(CustomAnimatorSystem
참조)에서 Update()
를 호출할 때 전환 매개 변수가 모두 충족되면 이동이 트리거 됩니다. 현 상태를 벗어나 새로운 상태로 진입하면 각 상태에서 SignalOnAnimatorStateExit
및 ISignalOnAnimatorStateEnter
가 발생됩니다.
주의: InputBufferSystem
에서 업데이트된 매개 변수는 모두 FixedPoint
타입입니다. 이 작업은 여러 프레임에 대해 새 입력을 수행하지 않은 플레이어가 이전 프레임에서 캐시 된 입력에 기반하여 실수로 공격을 수행하지 않도록 하기 위해 수행됩니다.
예를 들어 Uppercut_LP 상태는 다음 조건이 동시에 충족되는 한 AnyState에서 트리거될 수 있습니다.
- Z축(ZMotionF)의 움직임이 0보다 크고 0.15보다 작음
- 라이트 펀치 입력 시간이 0보다 크고 0.15보다 작음
- 캐릭터가 현재 땅에 있음(즉, InAir가 거짓임).
- 캐릭터는 현재 특수 공격을 수행할 수 있는 상태(즉, CanSpecialAtk이 true).
FixedPoint
매개 변수는 InputBufferSystem
에서 직접 업데이트되거나 InputCommandData
에 전달된 입력 시퀀스의 결과로 계속 업데이트됩니다. 반면 부울 매개 변수는 FighterAnimatorState
의 일부이며 캐릭터가 처음 현재 상태로 전환될 때 설정됩니다.