게임 패드 및 진동
이 페이지에서는 UWP(유니버설 Windows 플랫폼)용 [Windows.Gaming.Input.Gamepad][game pad] 및 관련 API를 사용하여 게임 패드에 대한 프로그래밍 기본 사항에 대해 설명합니다.
이 페이지를 읽으면 다음을 알게 됩니다.
- 연결된 게임 패드 및 사용자 목록을 수집하는 방법
- 게임 패드가 추가 또는 제거된 사실을 검색하는 방법
- 하나 이상의 게임 패드에서 입력을 읽는 방법
- 진동 및 임펄스 명령을 보내는 방법
- 게임 패드가 UI 탐색 장치로 동작하는 방식
게임 패드 개요
Xbox 무선 컨트롤러 및 Xbox 무선 컨트롤러 S와 같은 게임 패드는 범용 게임 입력 장치입니다. Xbox One의 표준 입력 장치이며, 키보드와 마우스를 선호하지 않는 경우 Windows 게이머에게 일반적으로 선택합니다. 게임 패드는 Windows 10 또는 Windows 11 및 Xbox UWP 앱에서 Windows.Gaming.Input 네임스페이스를 통해 지원됩니다.
Xbox One 게임 패드에는 방향 패드(또는 D 패드), A, B, X, Y, 보기, 메뉴 버튼, 왼쪽 및 오른쪽 섬스틱(thumbstick), 범퍼, 트리거, 총 4개의 진동 모터가 탑재되어 있습니다. 두 엄지스틱은 X축과 Y축에 이중 아날로그 판독값을 제공하며 안쪽으로 누를 때 단추 역할을 합니다. 각 트리거는 얼마나 끌어당겼는지를 나타내는 아날로그 판독값을 제공합니다.
참고 항목
Windows.Gaming.Input.Gamepad
는 표준 Xbox One 게임 패드와 동일한 컨트롤 레이아웃을 가진 Xbox 360 게임 패드도 지원합니다.
진동 및 임펄스 트리거
Xbox One 게임 패드는 강력하고 미묘한 게임 패드 진동을 위한 두 개의 독립 모터와 각 트리거에 날카로운 진동을 제공하기 위한 두 개의 전용 모터를 제공합니다(이 고유한 기능은 Xbox One 게임 패드 트리거를 임펄스 트리거라고 하는 이유입니다).
참고 항목
Xbox 360 게임 패드에는 임펄스 트리거가 탑재되어 있지 않습니다.
자세한 내용은 진동 및 임펄스 트리거 개요를 참조하세요.
섬스틱 데드존
중앙 위치의 미사용 엄지스틱은 X축과 Y축에서 매번 동일한 중립 판독값을 생성하는 것이 이상적입니다. 그러나 기계적 힘과 엄지스틱의 민감도로 인해 중앙 위치의 실제 판독값은 이상적인 중립 값과 유사하며 후속 판독값마다 다를 수 있습니다. 이러한 이유로 제조상의 차이, 기계적 마모, 기타 게임 패드 문제를 보완하기 위해 무시되는 이상적 중앙 위치 근처의 값 범위인 데드존을 항상 작게 사용해야 합니다.
더 큰 데드존은 의도적인 입력과 의도하지 않은 입력을 구분하는 간단한 전략을 제공합니다.
자세한 내용은 엄지스틱 읽기를 참조하세요.
UI 탐색
사용자 인터페이스 탐색을 위해 다양한 입력 장치를 지원해야 하는 부담을 줄이고 게임과 장치 간의 일관성을 유지하기 위해 대부분의 물리적 입력 장치는 UI 탐색 컨트롤러라는 별도의 논리 입력 장치 역할을 동시에 수행합니다. UI 탐색 컨트롤러는 입력 디바이스에서 UI 탐색 명령에 대한 일반적인 어휘를 제공합니다.
UI 탐색 컨트롤러 역할을 하는 게임 패드는 탐색 명령의 필수 집합을 왼쪽 섬스틱(thumbstick), D 패드, 보기, 메뉴, A, B 버튼에 매핑합니다.
탐색 명령 | 게임 패드 입력 |
---|---|
위로 | 왼쪽 엄지스틱 위로 / D 패드 위로 |
아래로 | 왼쪽 엄지스틱 아래로 / D 패드 아래로 |
Left | 왼쪽 엄지스틱 왼쪽으로 /D 패드 왼쪽으로 |
Right | 왼쪽 엄지스틱 오른쪽으로 / D 패드 오른쪽으로 |
보기 | 보기 버튼 |
메뉴 | 메뉴 버튼 |
수락 | A button |
취소 | B 버튼 |
또한 게임 패드는 모든 선택적 탐색 명령 집합을 다시 기본 입력에 매핑합니다.
탐색 명령 | 게임 패드 입력 |
---|---|
Page Up | 왼쪽 트리거 |
Page Down | 오른쪽 트리거 |
페이지 왼쪽 | 왼쪽 범퍼 |
페이지 오른쪽 | 오른쪽 범퍼 |
위로 스크롤 | 오른쪽 엄지스틱 위로 |
아래로 스크롤 | 오른쪽 엄지스틱 아래로 |
왼쪽으로 스크롤 | 오른쪽 엄지스틱 왼쪽으로 |
오른쪽으로 스크롤 | 오른쪽 엄지스틱 오른쪽으로 |
컨텍스트 1 | X 버튼 |
컨텍스트 2 | Y 버튼 |
컨텍스트 3 | 왼쪽 엄지 스틱을 누름 |
컨텍스트 4 | 오른쪽 엄지 스틱 누름 |
게임 패드 검색 및 추적
게임 패드는 시스템에서 관리되므로 헤드셋을 만들거나 초기화할 필요가 없습니다. 시스템은 연결된 게임 패드 및 이벤트 목록을 제공하여 게임 패드가 추가되거나 제거될 때 사용자에게 알립니다.
게임 패드 목록
Gamepad 클래스는 현재 연결된 게임 패드의 읽기 전용 목록인 정적 속성인 Gamepad를 제공합니다. 개발자는 연결된 게임 패드 중 일부에만 관심이 있기 때문에 Gamepads
속성을 통해 액세스하는 대신 자체 컬렉션을 유지 관리하는 것이 좋습니다.
다음 예제에서는 연결된 모든 게임 패드를 새 컬렉션에 복사합니다. 배경의 다른 스레드가 GamepadAdded 및 GamepadRemoved 이벤트의 이 컬렉션에 액세스하게 되므로 컬렉션을 읽거나 업데이트하는 코드에 대한 잠금을 만들어야 합니다.
auto myGamepads = ref new Vector<Gamepad^>();
critical_section myLock{};
for (auto gamepad : Gamepad::Gamepads)
{
// Check if the gamepad is already in myGamepads; if it isn't, add it.
critical_section::scoped_lock lock{ myLock };
auto it = std::find(begin(myGamepads), end(myGamepads), gamepad);
if (it == end(myGamepads))
{
// This code assumes that you're interested in all gamepads.
myGamepads->Append(gamepad);
}
}
private readonly object myLock = new object();
private List<Gamepad> myGamepads = new List<Gamepad>();
private Gamepad mainGamepad;
private void GetGamepads()
{
lock (myLock)
{
foreach (var gamepad in Gamepad.Gamepads)
{
// Check if the gamepad is already in myGamepads; if it isn't, add it.
bool gamepadInList = myGamepads.Contains(gamepad);
if (!gamepadInList)
{
// This code assumes that you're interested in all gamepads.
myGamepads.Add(gamepad);
}
}
}
}
게임 패드 추가 및 제거
게임 패드가 추가되거나 제거되면 GamepadAdded 및 GamepadRemoved 이벤트가 발생합니다. 이러한 이벤트에 대한 처리기를 등록하여 현재 연결된 게임 패드를 추적할 수 있습니다.
다음 예제에서는 추가된 게임 패드 추적을 시작합니다.
Gamepad::GamepadAdded += ref new EventHandler<Gamepad^>(Platform::Object^, Gamepad^ args)
{
// Check if the just-added gamepad is already in myGamepads; if it isn't, add
// it.
critical_section::scoped_lock lock{ myLock };
auto it = std::find(begin(myGamepads), end(myGamepads), args);
if (it == end(myGamepads))
{
// This code assumes that you're interested in all new gamepads.
myGamepads->Append(args);
}
}
Gamepad.GamepadAdded += (object sender, Gamepad e) =>
{
// Check if the just-added gamepad is already in myGamepads; if it isn't, add
// it.
lock (myLock)
{
bool gamepadInList = myGamepads.Contains(e);
if (!gamepadInList)
{
myGamepads.Add(e);
}
}
};
다음 예제에서는 제거된 게임 패드의 추적을 멈춥니다. 또한 게임 패드가 제거될 때 추적하는 게임 패드에 발생하는 상황을 처리해야 합니다. 예를 들어 이 코드는 한 게임 패드의 입력만 추적하고, 제거될 때 nullptr
로 설정하면 됩니다. 게임 패드가 활성 상태이면 모든 프레임을 확인하고, 컨트롤러가 연결되고 연결이 끊어질 때 입력을 수집하는 게임 패드를 업데이트해야 합니다.
Gamepad::GamepadRemoved += ref new EventHandler<Gamepad^>(Platform::Object^, Gamepad^ args)
{
unsigned int indexRemoved;
critical_section::scoped_lock lock{ myLock };
if(myGamepads->IndexOf(args, &indexRemoved))
{
if (m_gamepad == myGamepads->GetAt(indexRemoved))
{
m_gamepad = nullptr;
}
myGamepads->RemoveAt(indexRemoved);
}
}
Gamepad.GamepadRemoved += (object sender, Gamepad e) =>
{
lock (myLock)
{
int indexRemoved = myGamepads.IndexOf(e);
if (indexRemoved > -1)
{
if (mainGamepad == myGamepads[indexRemoved])
{
mainGamepad = null;
}
myGamepads.RemoveAt(indexRemoved);
}
}
};
자세한 내용은 게임용 입력 시스템을 참조하세요.
사용자 및 헤드셋
각 게임 패드를 사용자 계정과 연결하여 ID를 게임 플레이에 연결할 수 있으며, 음성 채팅 또는 게임 내 기능을 용이하게 하기 위해 헤드셋을 연결할 수 있습니다. 사용자 및 헤드셋 작업에 대한 자세한 내용은 사용자 및 장치 추적과 헤드셋을 참조하세요.
게임 패드 읽기
관심 있는 게임 패드를 식별한 후에는 해당 장치에서 입력을 수집할 준비가 된 것입니다. 그러나 익숙한 다른 종류의 입력과 달리 게임 패드는 이벤트를 발생시켜 상태 변경을 전달하지 않습니다. 대신, 플라이트 스틱을 직접 폴링하여 현재 상태의 규칙적인 판독값을 가져올 수 있습니다.
게임 패드 폴링
폴링은 정확한 시점에 내비게이션 장치의 스냅샷을 캡처합니다. 이러한 입력 수집 방법은 대부분의 게임에 적합합니다. 게임의 논리는 일반적으로 이벤트 기반 방식이 아닌 결정적 루프로 실행되기 때문입니다. 또한 시간을 두고 수집된 여러 단일 입력보다 한 번에 수집된 입력에서 게임 명령을 해석하는 것이 일반적으로 더 간단합니다.
GetCurrentReading을 호출하여 게임 패드를 폴링합니다. 이 함수는 게임 패드의 상태를 포함하는 GamepadReading을 반환합니다.
다음 예제에서는 게임 패드의 현재 상태를 폴링합니다.
auto gamepad = myGamepads[0];
GamepadReading reading = gamepad->GetCurrentReading();
Gamepad gamepad = myGamepads[0];
GamepadReading reading = gamepad.GetCurrentReading();
게임 패드 상태 외에도 각 판독값에는 상태가 검색된 시점을 정확하게 나타내는 타임스탬프가 포함됩니다. 타임스탬프는 이전 판독값의 타이밍 또는 게임 시뮬레이션의 타이밍과 관련되는 데 유용합니다.
엄지스틱 읽기
각 엄지스틱은 X축과 Y축에서 -1.0에서 +1.0 사이의 아날로그 판독값을 제공합니다. X축에서 값 -1.0은 가장 왼쪽의 엄지스틱 위치에 해당하며, +1.0 값은 가장 오른쪽 위치에 해당합니다. Y축에서 값 -1.0은 가장 아래의 엄지스틱 위치에 해당하며, +1.0 값은 가장 위쪽 위치에 해당합니다. 양 축에서 스틱이 중앙 위치에 있을 때 값은 약 0.0이지만 일반적으로 정밀 값은 후속 판독값마다 다릅니다. 이러한 변동을 완화하기 위한 전략은 이 섹션의 뒷부분에 설명되어 있습니다.
왼쪽 엄지스틱 X 축의 값은 GamepadReading 구조체의 LeftThumbstickX
속성에서 읽고 Y축의 값은 LeftThumbstickY
속성에서 읽습니다. 오른쪽 엄지스틱 X축의 값은 RightThumbstickX
속성에서 읽고 Y축의 값은 RightThumbstickY
속성에서 읽습니다.
float leftStickX = reading.LeftThumbstickX; // returns a value between -1.0 and +1.0
float leftStickY = reading.LeftThumbstickY; // returns a value between -1.0 and +1.0
float rightStickX = reading.RightThumbstickX; // returns a value between -1.0 and +1.0
float rightStickY = reading.RightThumbstickY; // returns a value between -1.0 and +1.0
double leftStickX = reading.LeftThumbstickX; // returns a value between -1.0 and +1.0
double leftStickY = reading.LeftThumbstickY; // returns a value between -1.0 and +1.0
double rightStickX = reading.RightThumbstickX; // returns a value between -1.0 and +1.0
double rightStickY = reading.RightThumbstickY; // returns a value between -1.0 and +1.0
엄지스틱 값을 읽을 때 엄지스틱이 중앙 위치에 있으면 중립 판독값 0.5가 안정적으로 생성되지 않지만 엄지스틱이 이동하여 중앙 위치로 돌아갈 때마다 0.5에 가까운 다른 값이 생성된다는 사실을 알 수 있습니다. 이러한 변화를 완화하기 위해 무시되는 이상적인 중심 위치 근처의 값 범위인 작은 데드존을 구현할 수 있습니다. 데드존을 구현하는 한 가지 방법은 엄지스틱이 중앙에서 얼마나 이동했는지 확인하고 선택한 거리보다 더 가까운 판독값을 무시하는 것입니다. 이 거리는 피타고라스의 정리를 사용해서 대략적으로 계산할 수 있습니다. 섬스틱(thumbstick) 판독값은 기본적으로 평면이 아닌 양극 값이므로 정확하지 않습니다. 이는 방사형 데드존을 생산합니다.
다음 예제는 피타고라스의 원리를 사용하는 기본 방사형 데드존을 보여 줍니다.
float leftStickX = reading.LeftThumbstickX; // returns a value between -1.0 and +1.0
float leftStickY = reading.LeftThumbstickY; // returns a value between -1.0 and +1.0
// choose a deadzone -- readings inside this radius are ignored.
const float deadzoneRadius = 0.1;
const float deadzoneSquared = deadzoneRadius * deadzoneRadius;
// Pythagorean theorem -- for a right triangle, hypotenuse^2 = (opposite side)^2 + (adjacent side)^2
auto oppositeSquared = leftStickY * leftStickY;
auto adjacentSquared = leftStickX * leftStickX;
// accept and process input if true; otherwise, reject and ignore it.
if ((oppositeSquared + adjacentSquared) > deadzoneSquared)
{
// input accepted, process it
}
double leftStickX = reading.LeftThumbstickX; // returns a value between -1.0 and +1.0
double leftStickY = reading.LeftThumbstickY; // returns a value between -1.0 and +1.0
// choose a deadzone -- readings inside this radius are ignored.
const double deadzoneRadius = 0.1;
const double deadzoneSquared = deadzoneRadius * deadzoneRadius;
// Pythagorean theorem -- for a right triangle, hypotenuse^2 = (opposite side)^2 + (adjacent side)^2
double oppositeSquared = leftStickY * leftStickY;
double adjacentSquared = leftStickX * leftStickX;
// accept and process input if true; otherwise, reject and ignore it.
if ((oppositeSquared + adjacentSquared) > deadzoneSquared)
{
// input accepted, process it
}
각 엄지스틱은 안쪽으로 누를 때 단추 역할을 합니다. 이 입력을 읽는 방법에 대한 자세한 내용은 단추 읽기를 참조하세요.
트리거 읽기
트리거는 0.0(완전히 해제됨)에서 1.0(완전히 눌려짐) 사이의 부동 소수점 값으로 표시됩니다. 왼쪽 트리거의 값은 GamepadReading 구조체의 LeftTrigger
속성에서 읽고 오른쪽 트리거의 값은 RightTrigger
속성에서 읽습니다.
float leftTrigger = reading.LeftTrigger; // returns a value between 0.0 and 1.0
float rightTrigger = reading.RightTrigger; // returns a value between 0.0 and 1.0
double leftTrigger = reading.LeftTrigger; // returns a value between 0.0 and 1.0
double rightTrigger = reading.RightTrigger; // returns a value between 0.0 and 1.0
버튼 읽기
각 게임 패드 버튼, 즉 D 패드의 네 방향, 왼쪽 및 오른쪽 범퍼, 왼쪽 및 오른쪽 섬스틱(thumbstick) 누름, A, B, X, Y, 보기, 메뉴는 버튼이 눌렸는지(아래쪽), 놓였는지(위쪽)를 나타내는 디지털 판독값을 제공합니다. 버튼 판독값은 효율을 위해 개별 부울 값으로 표현되지 않는 대신 GamepadButtons 열거로 표현되는 단일 비트 필드로 모두 압축됩니다.
버튼 값은 GamepadReading 구조체의 Buttons
속성에서 읽습니다. 이 속성은 비트 필드이기 때문에 비트 마스킹은 관심 있는 버튼의 값을 격리하는 데 사용됩니다. 해당 비트가 설정된 경우에는 버튼이 눌리고(아래), 그러지 않은 경우에는 놓입니다(위).
다음 예제에서는 A 버튼이 눌렸는지 확인합니다.
if (GamepadButtons::A == (reading.Buttons & GamepadButtons::A))
{
// button A is pressed
}
if (GamepadButtons.A == (reading.Buttons & GamepadButtons.A))
{
// button A is pressed
}
다음 예제에서는 A 버튼을 놓았는지 확인합니다.
if (GamepadButtons::None == (reading.Buttons & GamepadButtons::A))
{
// button A is released
}
if (GamepadButtons.None == (reading.Buttons & GamepadButtons.A))
{
// button A is released
}
버튼이 눌렸다가 놓이거나, 반대로 놓였다가 눌렸을 때 여러 개의 버튼이 눌렸거나 놓였는지 또는 일련의 버튼이 특정 방식으로 정렬되었는지(일부는 눌리고 일부는 놓임) 확인해야 하는 경우가 있습니다. 이러한 각 조건을 검색하는 방법에 대한 자세한 내용은 버튼 전환 감지 및 복잡한 버튼 정렬 검색을 참조하세요.
게임 패드 입력 샘플 실행
GamepadUWP 샘플(github)은 게임 패드에 연결하고 상태를 읽는 방법을 보여 줍니다.
진동 및 임펄스 트리거 개요
게임 패드 내부의 진동 모터는 사용자에게 촉각 피드백을 제공하기 위한 것입니다. 게임은 이 기능을 사용하여 더 큰 몰입감을 조성하고, 상태 정보(예: 손상) 통신, 중요한 개체에 대한 근접성 신호 또는 기타 창의적인 용도로 전달합니다.
Xbox One 게임 패드에는 총 4개의 독립 진동 모터가 장착되어 있습니다. 두 개는 게임 패드 본체에 있는 대형 모터입니다. 왼쪽 모터는 거친 고진폭 진동을 제공하고, 오른쪽 모터는 좀 더 부드럽고 미세한 진동을 제공합니다. 다른 두 모터는 각 트리거 안에 하나씩 있는 작은 모터로, 사용자의 트리거 손가락에 직접적으로 진동하는 날카로운 버스트를 제공합니다. Xbox One 게임 패드의 이 고유한 기능은 트리거를 임펄스 트리거라고 하는 이유입니다. 이러한 모터를 함께 오케스트레이션하면 다양한 촉각 감각이 생성될 수 있습니다.
진동 및 임펄스 사용
게임 패드 진동은 게임 패드 클래스의 진동 속성을 통해 제어됩니다. Vibration
은 4개의 부동 소수점 값으로 이루어진 GamepadVibration 구조의 인스턴스입니다. 각 값은 모터 중 하나의 강도를 나타냅니다.
Gamepad.Vibration
속성의 구성원은 직접 수정할 수 있지만 별도의 GamepadVibration
인스턴스를 원하는 값으로 초기화한 후 Gamepad.Vibration
속성으로 복사하여 실제 모터 강도를 모두 한 번에 변경하는 것이 좋습니다.
다음 예제에서는 모터 강도를 한 번에 모두 변경하는 방법을 보여 줍니다.
// get the first gamepad
Gamepad^ gamepad = Gamepad::Gamepads->GetAt(0);
// create an instance of GamepadVibration
GamepadVibration vibration;
// ... set vibration levels on vibration struct here
// copy the GamepadVibration struct to the gamepad
gamepad.Vibration = vibration;
// get the first gamepad
Gamepad gamepad = Gamepad.Gamepads[0];
// create an instance of GamepadVibration
GamepadVibration vibration = new GamepadVibration();
// ... set vibration levels on vibration struct here
// copy the GamepadVibration struct to the gamepad
gamepad.Vibration = vibration;
진동 모터 사용
왼쪽 및 오른쪽 진동 모터는 0.0(진동 없음)에서 1.0(가장 강렬한 진동) 사이의 부동 소수점 값을 사용합니다. 왼쪽 모터의 강도는 GamepadVibration 구조체의 LeftMotor
속성에 의해 설정되며, 오른쪽 모터의 강도는 RightMotor
속성에 의해 설정됩니다.
다음 예제에서는 진동 모터의 강도를 설정하고 게임 패드 진동을 활성화합니다.
GamepadVibration vibration;
vibration.LeftMotor = 0.80; // sets the intensity of the left motor to 80%
vibration.RightMotor = 0.25; // sets the intensity of the right motor to 25%
gamepad.Vibration = vibration;
GamepadVibration vibration = new GamepadVibration();
vibration.LeftMotor = 0.80; // sets the intensity of the left motor to 80%
vibration.RightMotor = 0.25; // sets the intensity of the right motor to 25%
mainGamepad.Vibration = vibration;
이러한 두 모터는 동일하지 않으므로 이러한 속성을 동일한 값으로 설정해도 한 모터에서 다른 모터와 동일한 진동이 발생하지 않습니다. 모든 값에서 왼쪽 모터는 오른쪽 모터보다 더 낮은 주파수의 더 강력한 진동을 재현하고, 동일한 값에서 오른쪽 모터는 더 높은 주파수의 더 미세한 진동을 재현합니다. 최대값에서도 왼쪽 모터는 오른쪽 모터의 높은 주파수를 생성할 수 없으며 오른쪽 모터는 왼쪽 모터의 높은 힘을 생성할 수 없습니다. 그럼에도 불구하고 모터는 게임 패드 본문에 의해 엄격하게 연결되기 때문에 모터의 특성이 다르고 다른 강도로 진동할 수 있더라도 플레이어는 진동을 완전히 독립적으로 경험하지 못합니다. 이 배열은 모터가 동일한 경우보다 더 넓고 표현적인 감각 범위를 생성 할 수 있습니다.
임펄스 트리거 사용
각 임펄스 트리거 모터는 0.0(진동 없음)과 1.0(가장 강렬한 진동) 사이의 부동 소수점 값을 사용합니다. 왼쪽 트리거 모터의 강도는 GamepadVibration 구조체의 LeftTrigger
속성에 의해 설정되며, 오른쪽 트리거의 강도는 RightTrigger
속성에 의해 설정됩니다.
다음 예제에서는 두 임펄스 트리거의 강도를 설정하고 활성화합니다.
GamepadVibration vibration;
vibration.LeftTrigger = 0.75; // sets the intensity of the left trigger to 75%
vibration.RightTrigger = 0.50; // sets the intensity of the right trigger to 50%
gamepad.Vibration = vibration;
GamepadVibration vibration = new GamepadVibration();
vibration.LeftTrigger = 0.75; // sets the intensity of the left trigger to 75%
vibration.RightTrigger = 0.50; // sets the intensity of the right trigger to 50%
mainGamepad.Vibration = vibration;
다른 모터와 달리 트리거 내의 두 진동 모터는 동일하므로 동일한 값에 대해 두 모터에서 동일한 진동을 생성합니다. 그러나 이러한 모터는 어떤 식으로든 엄격하게 연결되지 않으므로 플레이어는 진동을 독립적으로 경험합니다. 이 배열을 사용하면 완전히 독립적인 감각이 두 트리거로 동시에 전달될 수 있으며, 게임 패드 본문의 모터보다 더 구체적인 정보를 전달하는 데 도움이 됩니다.
게임 패드 진동 샘플 실행
GamepadVibrationUWP 샘플(github)은 게임 패드 진동 모터 및 임펄스 트리거를 사용하여 다양한 효과를 생성하는 방법을 보여 줍니다.