> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# IGameInput으로 네이티브 터치 인터페이스 구축하기

> IGameInput을 사용해 게임에 네이티브 터치 인터페이스 구축하기

플레이어가 모바일 디바이스에 게임을 스트리밍할 때 게임의 즐거움을 높일 수 있는 가장 좋은 방법 중 하나는 터치 컨트롤로 게임과 상호 작용할 수 있게 하는 것입니다. XBOX 게임 스트리밍은 [Touch Adaptation Kit](/build/core-features/common/game-streaming/game-streaming-touch-touch-adaptation-kit-overview)를 사용하여 게임 위에 터치 컨트롤을 오버레이하는 기능을 지원하며, 가상 게임패드를 사용해 게임을 플레이하는 것이 자연스러운 게임의 많은 화면에서 훌륭한 선택이 될 수 있습니다. 그러나 메뉴, 지도, 인벤토리 화면 등과 같은 게임의 부분에서는 터치 입력으로 게임과 직접 상호 작용하는 것이 더 자연스러울 수 있습니다.

예를 들어, 플레이어가 메뉴 옵션을 탭하여 상호 작용하거나 휴대폰 제스처로 지도를 확대하고 스크롤하는 것은 매우 자연스럽습니다. Microsoft Game Development Kit(GDK)은 이 네이티브 터치 인터페이스를 게임에 구축할 수 있는 API를 제공하여 진정한 모바일 경험처럼 느껴지게 합니다.

Touch Adaptation Kit과 네이티브 터치는 상호 배타적이지 않습니다. 게임에서 가장 적합한 곳에 각 형태의 터치 입력을 사용하여 두 가지를 모두 사용할 수 있습니다. 예를 들어, 메인 게임 플레이 루프에는 Touch Adaptation Kit을 사용하는 한편, 네이티브 터치 메뉴를 사용하는 것은 타이틀의 터치 입력 전략을 구성하는 합리적인 방법일 수 있습니다.

<Note>네이티브 터치를 사용하는 게임을 개발하는 경우 계정 관리자에게 알려주세요. 게임이 소매 환경에 배포될 때 게임이 터치 이벤트를 받을 수 있도록 XBOX Game Streaming 백엔드 서비스를 구성해야 합니다.</Note>

네이티브 터치는 [IGameInputReading::GetTouchState](/reference/input/gameinput/deprecated/interfaces/igameinputreading/methods/igameinputreading_gettouchstate) API를 통해 게임에서 사용할 수 있습니다. 이 API는 플레이어가 화면을 만지고 있는 현재 손가락 집합을 나타내는 현재 터치 포인트 집합을 제공합니다.

이러한 터치 포인트를 press, move, release 이벤트로 변환하려면 각 프레임에서 그 상태를 추적하는 것이 유용할 수 있습니다.

* 이전 프레임에는 없었지만 현재 프레임에 있는 터치 포인트는 새 터치 press입니다.
* 이전 프레임에 있었고 현재 프레임에도 여전히 있는 터치 포인트는 터치의 좌표가 변경되지 않은 경우 move 또는 no-op입니다.
* 이전 프레임에는 있었지만 더 이상 없는 터치 포인트는 터치 release입니다.

이러한 press, move 및 release 이벤트를 빌드하는 매우 기본적인 입력 루프는 다음과 같습니다.

```cpp theme={null}
struct TouchPoint
{
    // GameInputTouchState.touchId corresponding to this point
    uint64_t Id = 0;    

    // X pixel being touched
    uint32_t X = 0;

    // Y pixel being touched
    uint32_t Y = 0;

    // Is this entry in the array of touch points currently being used to track a touch
    bool IsInUse = false;

    // Is this TouchPoint tracking a finger which is currently touching the screen
    bool IsTouchActive = false;
};

// Touch points currently being tracked
std::array<TouchPoint, 10> g_touchPoints = {};

extern IGameInput* g_gameInput;
extern uint32_t g_frameWidth;
extern uint32_t g_frameHeight;

void TouchPointPressed(const TouchPoint& touchPoint);
void TouchPointMoved(const TouchPoint& touchPoint);
void TouchPointReleased(const TouchPoint& touchPoint);


void ProcessTouchInput()
{
    // Reset the active touch state from the previous frame
    for (TouchPoint& touchPoint : g_touchPoints)
    {
        touchPoint.IsTouchActive = false;
    }

    // Process any new touch points for this frame
    Microsoft::WRL::ComPtr<IGameInputReading> reading = nullptr;
    if (SUCCEEDED(g_gameInput->GetCurrentReading(GameInputKindTouch, nullptr, &reading)))
    {
        uint32_t touchCount = reading->GetTouchCount();
        if (touchCount > 0)
        {
            std::vector<GameInputTouchState> touchStates(touchCount);
            touchCount = reading->GetTouchState(touchCount, touchStates.data());

            for (const GameInputTouchState& touchState : touchStates)
            {
                const uint32_t x = static_cast<uint32_t>(touchState.positionX * g_frameWidth);
                const uint32_t y = static_cast<uint32_t>(touchState.positionY * g_frameHeight);

                // Check to see if we are already tracking this touch point
                auto existingPoint = std::find_if(std::begin(g_touchPoints), std::end(g_touchPoints), [id = touchState.touchId](const TouchPoint& point)
                {
                    return point.IsInUse && point.Id == id;
                });

                if (existingPoint != g_touchPoints.end())
                {
                    // We were already tracking the point - it is still alive this frame, but it may have
                    // also moved position.
                    existingPoint->IsTouchActive = true;
                    if (existingPoint->X != x || existingPoint->Y != y)
                    {
                        existingPoint->X = x;
                        existingPoint->Y = y;
                        TouchPointMoved(*existingPoint);
                    }
                }
                else
                {
                    // This is a new touch point. Start tracking it and treat it as a press
                    auto insertPoint = std::find_if(std::begin(g_touchPoints), std::end(g_touchPoints), [](const TouchPoint& point)
                    {
                        return !point.IsInUse;
                    });

                    if (insertPoint != std::end(g_touchPoints))
                    {
                        insertPoint->Id = touchState.touchId;
                        insertPoint->X = x;
                        insertPoint->Y = y;
                        insertPoint->IsInUse = true;
                        insertPoint->IsTouchActive = true;

                        TouchPointPressed(*insertPoint);
                    }
                }
            }
        }

        // Look for any points which were pressed last frame but are no longer pressed this frame
        // and treat those as touch releases
        for (TouchPoint& touchPoint : g_touchPoints)
        {
            if (touchPoint.IsInUse && !touchPoint.IsTouchActive)
            {
                TouchPointReleased(touchPoint);
                touchPoint = TouchPoint{};
            }
        }
    }
}
```


## Related topics

- [터치 시작하기](/ko/build/core-features/common/game-streaming/game-streaming-getting-started-with-touch.md)
- [터치 컨트롤을 구축하기 위한 디자이너 가이드](/ko/build/core-features/common/game-streaming/building-touch-layouts/game-streaming-tak-designers-guide.md)
- [PlayFab Multiplayer Unity 플러그인 개요](/ko/services/playfab/multiplayer/lobby/lobby-matchmaking-sdks/multiplayer-unity-overview.md)
- [IGameInput::GetPreviousReading](/ko/reference/input/gameinput/interfaces/igameinput/methods/igameinput_getpreviousreading.md)
- [IGameInput::GetNextReading](/ko/reference/input/gameinput/interfaces/igameinput/methods/igameinput_getnextreading.md)
