Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Naučte se přidávat základní dotykové ovládací prvky do hry C++ pro Univerzální platformu Windows (UPW) pomocí DirectX. Ukážeme vám, jak přidat dotykové ovládací prvky pro přesunutí kamery s pevnou rovinou v prostředí Direct3D, kde přetažení prstem nebo perem posune perspektivu kamery.
Tyto ovládací prvky můžete začlenit do her, ve kterých chcete, aby hráč posunul nebo posouval pohled přes 3D prostředí, jako je mapa nebo herní pole. Například ve strategii nebo puzzle hry můžete pomocí těchto ovládacích prvků umožnit hráči zobrazit herní prostředí, které je větší než obrazovka posouváním doleva nebo doprava.
Poznámka Náš kód také funguje s ovládacími prvky pro posouvání pomocí myši. Události související s ukazatelem jsou abstrahovány rozhraními API prostředí Windows Runtime, takže mohou zpracovávat události ukazatele založené na dotykovém ovládání nebo ukazatele myši.
Cíle
- Vytvořte jednoduchý dotykový ovladač pro posun stabilní kamery ve hře DirectX.
Nastavte základní infrastrukturu pro dotykové události
Nejprve definujeme základní typ kontroleru CameraPanController v tomto případě. Tady definujeme kontroler jako abstraktní myšlenku a sadu chování, které může uživatel provést.
Třída CameraPanController je sbírka pravidelně aktualizovaných informací o stavu ovladače kamery a poskytuje způsob, jak naše aplikace může získávat tyto informace ze své aktualizační smyčky.
using namespace Windows::UI::Core;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::Devices::Input;
#include <directxmath.h>
// Methods to get input from the UI pointers
ref class CameraPanController
{
}
Teď vytvoříme hlavičku, která definuje stav kontroleru kamery a základní metody a obslužné rutiny událostí, které implementují interakce kontroleru kamery.
ref class CameraPanController
{
private:
// Properties of the controller object
DirectX::XMFLOAT3 m_position; // the position of the camera
// Properties of the camera pan control
bool m_panInUse;
uint32 m_panPointerID;
DirectX::XMFLOAT2 m_panFirstDown;
DirectX::XMFLOAT2 m_panPointerPosition;
DirectX::XMFLOAT3 m_panCommand;
internal:
// Accessor to set the position of the controller
void SetPosition( _In_ DirectX::XMFLOAT3 pos );
// Accessor to set the fixed "look point" of the controller
DirectX::XMFLOAT3 get_FixedLookPoint();
// Returns the position of the controller object
DirectX::XMFLOAT3 get_Position();
public:
// Methods to get input from the UI pointers
void OnPointerPressed(
_In_ Windows::UI::Core::CoreWindow^ sender,
_In_ Windows::UI::Core::PointerEventArgs^ args
);
void OnPointerMoved(
_In_ Windows::UI::Core::CoreWindow^ sender,
_In_ Windows::UI::Core::PointerEventArgs^ args
);
void OnPointerReleased(
_In_ Windows::UI::Core::CoreWindow^ sender,
_In_ Windows::UI::Core::PointerEventArgs^ args
);
// Set up the Controls supported by this controller
void Initialize( _In_ Windows::UI::Core::CoreWindow^ window );
void Update( Windows::UI::Core::CoreWindow ^window );
}; // Class CameraPanController
Soukromá pole obsahují aktuální stav ovladače fotoaparátu. Pojďme se na ně podívat.
- m_position je pozice kamery v prostoru scény. V tomto příkladu je hodnota souřadnic z pevná na 0. K reprezentaci této hodnoty bychom mohli použít directX::XMFLOAT2, ale pro účely této ukázky a budoucí rozšiřitelnosti používáme DirectX::XMFLOAT3. Tuto hodnotu předáme vlastnosti get_Position samotné aplikaci, aby mohla odpovídajícím způsobem aktualizovat zorné pole.
- m_panInUse je logická hodnota, která označuje, zda je operace posouvání aktivní; nebo konkrétně, jestli se hráč dotkne obrazovky a přesune kameru.
- m_panPointerID je jedinečné ID ukazatele. V ukázce to nebudeme používat, ale je vhodné přidružit třídu stavu kontroleru ke konkrétnímu ukazateli.
- m_panFirstDown je bod na obrazovce, na kterém se hráč poprvé dotkl obrazovky nebo během akce posouvání kamery kliknul myší. Tuto hodnotu použijeme později k nastavení neaktivní zóny, aby se zabránilo zatěžování, když se obrazovka dotkne, nebo když se myš trochu zatřese.
- m_panPointerPosition je bod na obrazovce, na kterém hráč právě přesunul ukazatel. Používáme ho k určení směru, kterým se hráč chtěl pohybovat, tím, že ho prozkoumáme vzhledem k m_panFirstDown.
- m_panCommand je posledním vypočítaným příkazem pro ovladač fotoaparátu: nahoru, dolů, doleva nebo doprava. Vzhledem k tomu, že pracujeme s kamerou upevněnou v rovině x-y, může se místo toho jednat o hodnotu DirectX::XMFLOAT2.
Tyto tři obslužné rutiny událostí používáme k aktualizaci informací o stavu kontroleru kamery.
- OnPointerPressed je obslužná rutina události, kterou naše aplikace volá, když hráč stiskne prst na dotykovou plochu a ukazatel se přesune na souřadnice stisku.
- onPointerMoved je obslužná rutina události, kterou aplikace volá, když hráč potáhne prstem přes dotykovou plochu. Aktualizuje se novými souřadnicemi cesty přetažení.
- OnPointerReleased je obslužná rutina události, kterou aplikace volá, když přehrávač odebere prst z dotykové plochy.
Nakonec tyto metody a vlastnosti použijeme k inicializaci, přístupu a aktualizaci informací o stavu kontroleru kamery.
- Inicializace je obslužná rutina události, kterou naše aplikace volá k inicializaci ovládacích prvků a připojí je k objektu CoreWindow , který popisuje vaše okno zobrazení.
- SetPosition je metoda, kterou naše aplikace volá k nastavení (x, y a z) souřadnic vašich ovládacích prvků v prostoru scény. Všimněte si, že naše souřadnice z je v průběhu tohoto kurzu 0.
- get_Position je vlastnost, ke které naše aplikace přistupuje, aby získala aktuální pozici kamery v prostoru scény. Tuto vlastnost použijete jako způsob komunikace aktuální pozice fotoaparátu do aplikace.
- get_FixedLookPoint je vlastnost, ke které naše aplikace přistupuje, aby získala aktuální bod, ke kterému má kamera kontroleru přístup. V tomto příkladu je uzamčen kolmo k rovině x-y.
- Aktualizace je metoda, která čte stav kontroleru a aktualizuje pozici kamery. Neustále voláte tuto <něco> z hlavní smyčky aplikace, aby se aktualizovala data kontroléru fotoaparátu a umístění kamery v prostoru scény.
Teď máte všechny komponenty, které potřebujete k implementaci dotykových ovládacích prvků. Můžete zjistit, kdy a kde došlo k událostem dotykového ovládání nebo pohybu ukazatele myši a jaká akce byla provedena. Můžete nastavit polohu a orientaci kamery vzhledem k prostoru scény a sledovat změny. Nakonec můžete novou pozici kamery sdělit volající aplikaci.
Teď tyto části propojíme.
Vytvořte základní dotykové události
Dispečer událostí prostředí Windows Runtime poskytuje 3 události, které chceme, aby naše aplikace zpracovávala:
Tyto události jsou implementovány u typu CoreWindow. Předpokládáme, že máte objekt CoreWindow, se kterým chcete pracovat. Další informace najdete v tématu Jak nastavit aplikaci pro UPW C++ tak, aby zobrazovala zobrazení DirectX.
Tyto události se aktivují, když je naše aplikace spuštěná, obslužné rutiny aktualizují informace o stavu kontroleru fotoaparátu definované v našich privátních polích.
Nejprve naplníme obslužné rutiny událostí dotykového ukazatele. V první obslužné rutině události OnPointerPressedzískáme souřadnice x a y ukazatele z CoreWindow, které spravuje naše zobrazení, když se uživatel dotkne obrazovky nebo klikne myší.
OnPointerPressed
void CameraPanController::OnPointerPressed(
_In_ CoreWindow^ sender,
_In_ PointerEventArgs^ args)
{
// Get the current pointer position.
uint32 pointerID = args->CurrentPoint->PointerId;
DirectX::XMFLOAT2 position = DirectX::XMFLOAT2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );
auto device = args->CurrentPoint->PointerDevice;
auto deviceType = device->PointerDeviceType;
if ( !m_panInUse ) // If no pointer is in this control yet.
{
m_panFirstDown = position; // Save the location of the initial contact.
m_panPointerPosition = position;
m_panPointerID = pointerID; // Store the id of the pointer using this control.
m_panInUse = TRUE;
}
}
Tuto obslužnou rutinu používáme k tomu, abychom aktuální instanci CameraPanController informovali, že řadič fotoaparátu by měl být považován za aktivní nastavením hodnoty m_panInUse na TRUE. Když aplikace volá update , použije aktuální data pozice k aktualizaci oblasti zobrazení.
Teď, když jsme nastavili základní hodnoty pohybu fotoaparátu, když se uživatel dotkne obrazovky nebo stiskne kliknutí v okně zobrazení, musíme určit, co dělat, když uživatel přetáhne obrazovku nebo přesune myš s tlačítkem stisknutou klávesou.
OnPointerMoved obslužná rutina se aktivuje při každém pohybu ukazatele, kdy hráč pohybuje po obrazovce. Potřebujeme, aby aplikace věděla o aktuálním umístění ukazatele, a to je způsob, jak to děláme.
OnPointerMoved
void CameraPanController::OnPointerMoved(
_In_ CoreWindow ^sender,
_In_ PointerEventArgs ^args)
{
uint32 pointerID = args->CurrentPoint->PointerId;
DirectX::XMFLOAT2 position = DirectX::XMFLOAT2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );
m_panPointerPosition = position;
}
Nakonec musíme deaktivovat chování posouvání kamery, když se hráč přestane dotýkat obrazovky. Používáme OnPointerReleased, která se volá při aktivaci PointerReleased, čímž nastavíme m_panInUse na FALSE, vypneme pohyb posunu kamery a nastavíme ID ukazatele na 0.
OnPointerReleased
void CameraPanController::OnPointerReleased(
_In_ CoreWindow ^sender,
_In_ PointerEventArgs ^args)
{
uint32 pointerID = args->CurrentPoint->PointerId;
DirectX::XMFLOAT2 position = DirectX::XMFLOAT2( args->CurrentPoint->Position.X, args->CurrentPoint->Position.Y );
m_panInUse = FALSE;
m_panPointerID = 0;
}
Inicializace dotykových ovládacích prvků a stavu kontroleru
Připojme události a inicializujme všechna základní stavová pole ovladače kamery.
Inicializovat
void CameraPanController::Initialize( _In_ CoreWindow^ window )
{
// Start receiving touch/mouse events.
window->PointerPressed +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &CameraPanController::OnPointerPressed);
window->PointerMoved +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &CameraPanController::OnPointerMoved);
window->PointerReleased +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &CameraPanController::OnPointerReleased);
// Initialize the state of the controller.
m_panInUse = FALSE;
m_panPointerID = 0;
// Initialize this as it is reset on every frame.
m_panCommand = DirectX::XMFLOAT3( 0.0f, 0.0f, 0.0f );
}
Inicializace vezme odkaz na instanci CoreWindow aplikace jako parametr a zaregistruje obslužné rutiny událostí, které jsme vyvinuli na příslušné události na tomto CoreWindow.
Získání a nastavení polohy ovladače kamery
Pojďme definovat některé metody, jak získat a nastavit pozici ovladače kamery v prostoru scény.
void CameraPanController::SetPosition( _In_ DirectX::XMFLOAT3 pos )
{
m_position = pos;
}
// Returns the position of the controller object
DirectX::XMFLOAT3 CameraPanController::get_Position()
{
return m_position;
}
DirectX::XMFLOAT3 CameraPanController::get_FixedLookPoint()
{
// For this sample, we don't need to use the trig functions because our
// look point is fixed.
DirectX::XMFLOAT3 result= m_position;
result.z += 1.0f;
return result;
}
SetPosition je veřejná metoda, kterou můžeme volat z naší aplikace, pokud potřebujeme nastavit pozici ovladače fotoaparátu na určitý bod.
get_Position je naše nejdůležitější veřejná vlastnost: je to způsob, jakým naše aplikace získá aktuální pozici ovladače fotoaparátu v prostoru scény, aby mohl odpovídajícím způsobem aktualizovat oblast zobrazení.
get_FixedLookPoint je veřejná vlastnost, která v tomto příkladu získá bod pohledu, který je kolmý na rovinu x-y. Tuto metodu můžete změnit tak, aby se při výpočtu hodnot souřadnic x, y a z použily trigonometrické funkce sin a cos, pokud chcete vytvořit více šikmých úhlů pro pevnou kameru.
Aktualizace informací o stavu kontroleru fotoaparátu
Teď provádíme výpočty, které převádějí informace o souřadnicích ukazatele sledovaných v m_panPointerPosition na nové souřadnicové informace odpovídající prostoru naší 3D scény. Naše aplikace volá tuto metodu pokaždé, když aktualizujeme hlavní smyčku aplikace. V něm vypočítáme informace o nové pozici, které chceme předat aplikaci, která se používá k aktualizaci matice zobrazení před projekcí do oblasti zobrazení.
void CameraPanController::Update( CoreWindow ^window )
{
if ( m_panInUse )
{
pointerDelta.x = m_panPointerPosition.x - m_panFirstDown.x;
pointerDelta.y = m_panPointerPosition.y - m_panFirstDown.y;
if ( pointerDelta.x > 16.0f ) // Leave 32 pixel-wide dead spot for being still.
m_panCommand.x += 1.0f;
else
if ( pointerDelta.x < -16.0f )
m_panCommand.x += -1.0f;
if ( pointerDelta.y > 16.0f )
m_panCommand.y += 1.0f;
else
if (pointerDelta.y < -16.0f )
m_panCommand.y += -1.0f;
}
DirectX::XMFLOAT3 command = m_panCommand;
// Our velocity is based on the command.
DirectX::XMFLOAT3 Velocity;
Velocity.x = command.x;
Velocity.y = command.y;
Velocity.z = 0.0f;
// Integrate
m_position.x = m_position.x + Velocity.x;
m_position.y = m_position.y + Velocity.y;
m_position.z = m_position.z + Velocity.z;
// Clear the movement input accumulator for use during the next frame.
m_panCommand = DirectX::XMFLOAT3( 0.0f, 0.0f, 0.0f );
}
Protože nechceme, aby naše kamera při posouvání cukala kvůli roztřesení při dotyku nebo pohybu myší, nastavíme kolem ukazatele mrtvou zónu o průměru 32 pixelů. Máme také hodnotu rychlosti, která v tomto případě je 1:1 s procházením pixelů ukazatelem přes mrtvou zónu. Toto chování můžete upravit tak, aby zpomalilo nebo urychlilo rychlost pohybu.
Aktualizace matice zobrazení s novou polohou kamery
Nyní můžeme získat souřadnici prostoru scény, na které je naše kamera zaměřená, a která se aktualizuje pokaždé, když aplikaci řeknete, aby to udělala (například každých 60 sekund v hlavní smyčce aplikace). Tento pseudokód naznačuje chování volání, které můžete implementovat:
myCameraPanController->Update( m_window );
// Update the view matrix based on the camera position.
myCamera->MyMethodToComputeViewMatrix(
myController->get_Position(), // The position in the 3D scene space.
myController->get_FixedLookPoint(), // The point in the space we are looking at.
DirectX::XMFLOAT3( 0, 1, 0 ) // The axis that is "up" in our space.
);
Gratulujeme! Implementovali jste ve hře jednoduchou sadu ovládacích prvků pro posouvání fotoaparátu.