當玩家將您的遊戲串流到其行動裝置時,提升遊戲樂趣的最佳方式之一,就是讓他們能夠使用觸控控制項與您的遊戲互動。XBOX 遊戲串流支援使用 Touch Adaptation Kit 在遊戲上方疊加觸控控制項,對於遊戲中許多以虛擬遊戲手把遊玩是自然方式的畫面而言,這會是很好的選擇。不過,對於遊戲中的選單、地圖、物品欄畫面等部分,直接使用觸控輸入與遊戲互動可能更為自然。例如,玩家很自然地會想點選選單選項來與其互動,或想使用手機手勢來放大和捲動地圖。Microsoft Game Development Kit (GDK) 提供的 API 可讓您在遊戲中建置這種原生觸控介面,使其感覺像是真正的行動體驗。Touch Adaptation Kit 與原生觸控並非互斥:您可以在遊戲中同時使用兩者,在最適合您遊戲的地方使用各種形式的觸控輸入。例如,使用原生觸控選單,同時在主要遊戲迴圈中使用 Touch Adaptation Kit,可能是建構遊戲觸控輸入策略的合理方式。
如果您正在建置使用原生觸控的遊戲,請通知您的客戶經理。必須設定 XBOX Game Streaming 後端服務,您的遊戲部署到零售環境時才能接收觸控事件。
原生觸控是透過 IGameInputReading::GetTouchState API 提供給您的遊戲。此 API 會提供目前的觸控點集合,代表玩家目前用來觸碰螢幕的手指集合。若要將這些觸控點轉換為按下、移動和放開事件,在每個畫面之間追蹤其狀態會很有幫助。
任何在前一個畫面中不存在、但在目前畫面中存在的觸控點,都是新的觸控按下。
任何在前一個畫面中存在、且在目前畫面中仍然存在的觸控點,若觸控的座標已變更即為移動,否則為無作業。
在前一個畫面中存在、但已不再存在的觸控點,則為觸控放開。
建置這些按下、移動和放開事件的非常基本輸入迴圈,可能如下所示:
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 trackedstd::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{}; } } }}
Last modified on October 6, 2026
Was this page helpful?
⌘I
Assistant
Responses are generated using AI and may contain mistakes.