Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Lär dig hur du lägger till grundläggande pekkontroller i ditt UWP-C++-spel (Universal Windows Platform) med DirectX. Vi visar hur du lägger till touchbaserade kontroller för att flytta en kamera med fast plan i en Direct3D-miljö, där dra med ett finger eller en penna flyttar kameraperspektivet.
Du kan införliva dessa kontroller i spel där du vill att spelaren ska dra för att rulla eller panorera över en 3D-miljö, till exempel en karta eller ett spelfält. I en strategi eller ett pusselspel kan du till exempel använda dessa kontroller för att låta spelaren se en spelmiljö som är större än skärmen genom att panorera åt vänster eller höger.
Obs Vår kod fungerar också med musbaserade panoreringskontroller. Pekarrelaterade händelser abstraheras av Windows Runtime-API:er, så att de kan hantera antingen touch- eller musbaserade pekarhändelser.
Målsättningar
- Skapa en enkel pekdragkontroll för panorering av en kamera med fast plan i ett DirectX-spel.
Konfigurera den grundläggande infrastrukturen för touch-händelser
Först definierar vi vår grundläggande styrenhetstyp, CameraPanController, i det här fallet. Här definierar vi en kontrollant som en abstrakt idé, den uppsättning beteenden som användaren kan utföra.
Klassen CameraPanController är en regelbundet uppdaterad samling med information om kamerastyrenhetens tillstånd och ger appen ett sätt att hämta den informationen från uppdateringsloopen.
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
{
}
Nu ska vi skapa en rubrik som definierar tillståndet för kamerastyrenheten och de grundläggande metoderna och händelsehanterare som implementerar interaktionen mellan kamerastyrenheten.
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
De privata fälten innehåller kamerastyrenhetens aktuella tillstånd. Nu ska vi granska dem.
- m_position är kamerans position i scenutrymmet. I det här exemplet anges z-koordinatvärdet till 0. Vi kan använda en DirectX::XMFLOAT2 för att representera det här värdet, men för det här exemplet och framtida utökningsbarhet använder vi en DirectX::XMFLOAT3. Vi skickar det här värdet via egenskapen get_Position till själva appen så att den kan uppdatera visningsporten i enlighet med detta.
- m_panInUse är ett booleskt värde som anger om en panoreringsåtgärd är aktiv. eller, mer specifikt, om spelaren rör skärmen och flyttar kameran.
- m_panPointerID är ett unikt ID för pekaren. Vi använder inte detta i exemplet, men det är en bra idé att associera klassen för kontrollanttillstånd med en specifik pekare.
- m_panFirstDown är den punkt på skärmen där spelaren först rörde vid skärmen eller klickade på musen under kamerapannan. Vi använder det här värdet senare för att ange en död zon för att förhindra jitter när skärmen vidrörs, eller om musen skakar lite.
- m_panPointerPosition är den punkt på skärmen där spelaren för närvarande har flyttat pekaren. Vi använder den för att avgöra vilken riktning spelaren ville flytta genom att undersöka den i förhållande till m_panFirstDown.
- m_panCommand är det slutliga beräknade kommandot för kamerastyrenheten: uppåt, nedåt, vänster eller höger. Eftersom vi arbetar med en kamera som är fast på x-y-planet kan detta vara ett DirectX::XMFLOAT2-värde i stället.
Vi använder dessa tre händelsehanterare för att uppdatera statusinformationen för kamerastyrenheten.
- OnPointerPressed är en händelsehanterare som appen anropar när spelarna trycker ett finger på pekytan och pekaren flyttas till pressens koordinater.
- OnPointerMoved är en händelsehanterare som appen anropar när spelaren sveper ett finger över touchytan. Den uppdateras med de nya koordinaterna för dragsökvägen.
- OnPointerReleased är en händelsehanterare som appen anropar när spelaren tar bort pressfingret från touchytan.
Slutligen använder vi dessa metoder och egenskaper för att initiera, komma åt och uppdatera kamerastyrenhetens tillståndsinformation.
- Initiera är en händelsehanterare som appen anropar för att initiera kontrollerna och koppla dem till objektet CoreWindow som beskriver visningsfönstret.
- SetPosition är en metod som appen anropar för att ange koordinaterna (x, y och z) för kontrollerna i scenområdet. Observera att vår z-koordinat är 0 i den här handledningen.
- get_Position är en egenskap som vår app har åtkomst till för att hämta kamerans aktuella position i scenutrymmet. Du använder den här egenskapen som ett sätt att kommunicera den aktuella kamerapositionen till appen.
- get_FixedLookPoint är en egenskap som vår app kommer åt för att hämta den aktuella punkt som styrenhetskameran är riktad mot. I det här exemplet är det låst normalt till x-y-planet.
- Update är en metod som läser kontrollantens tillstånd och uppdaterar kamerapositionen. Du kallar kontinuerligt denna <> från appens huvudloop för att uppdatera kameraenhetsdata och kamerapositionen i scenutrymmet.
Nu har du här alla komponenter som du behöver för att implementera pekkontroller. Du kan identifiera när och var touch- eller muspekarehändelserna har inträffat och vad åtgärden är. Du kan ange kamerans position och orientering i förhållande till scenutrymmet och spåra ändringarna. Slutligen kan du kommunicera den nya kamerapositionen till den anropande appen.
Nu ska vi koppla ihop de här delarna.
Skapa de grundläggande touchhändelserna
Händelseutskickaren för Windows Runtime innehåller tre händelser som vi vill att vår app ska hantera:
Dessa händelser implementeras på CoreWindow typ. Vi antar att du har ett CoreWindow- objekt att arbeta med. Mer information finns i Så här konfigurerar du din UWP C++-app för att visa en DirectX-vy.
När dessa händelser utlöses när vår app körs uppdaterar hanterarna informationen om kamerastyrenhetens tillstånd som definierats i våra privata fält.
Först ska vi fylla i händelsehanterare för pekpekare. I den första händelsehanteraren OnPointerPressedfår vi x-y-koordinaterna för pekaren från CoreWindow- som hanterar vår skärm när användaren rör vid skärmen eller klickar på musen.
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;
}
}
Vi använder den här hanteraren för att låta den aktuella CameraPanController instans veta att kamerastyrenheten ska behandlas som aktiv genom att ställa in m_panInUse till TRUE. När appen anropar Update använder den då aktuella positionsdata för att uppdatera visningsporten.
Nu när vi har fastställt basvärdena för kamerarörelsen när användaren rör vid skärmen eller klickar på tryckningar i visningsfönstret måste vi bestämma vad som ska göras när användaren antingen drar skärmtryckningen eller flyttar musen med knappen intryckt.
OnPointerMoved händelsehanteraren utlöses när pekaren rör sig, vid varje ögonblick som spelaren drar den över skärmen. Vi måste hålla appen medveten om pekarens aktuella plats och det är så vi gör.
OnPointer har flyttats
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;
}
Slutligen måste vi inaktivera kamerapannans beteende när spelaren slutar röra skärmen. Vi använder OnPointerReleased, som anropas när PointerReleased utlöses, för att ställa in m_panInUse på FALSE och stänga av kamerans panoreringsrörelse och ange pekar-ID till 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;
}
Initiera touch-kontrollerna och kontrollanttillståndet
Vi kopplar händelserna och initierar alla grundläggande tillståndsfält i kamerastyrenheten.
Initiera
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 );
}
Initiera tar en referens till appens CoreWindow instans som parameter och registrerar de händelsehanterare vi har utvecklat till de lämpliga händelserna på denna CoreWindow.
Hämta och ställa in kamerastyrenhetens position
Nu ska vi definiera några metoder för att hämta och ange kamerastyrenhetens position i scenutrymmet.
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 är en offentlig metod som vi kan anropa från vår app om vi behöver ange kamerastyrenhetens position till en viss punkt.
get_Position är vår viktigaste offentliga egendom: det är så vår app får kamerastyrenhetens aktuella position i scenutrymmet så att den kan uppdatera visningsporten i enlighet med detta.
get_FixedLookPoint är en offentlig egenskap som i det här exemplet hämtar en look point som är normal för x-y-planet. Du kan ändra den här metoden till att använda trigonometriska funktioner, sin och cos, när du beräknar x-, y- och z-koordinatvärdena om du vill skapa fler sneda vinklar för den fasta kameran.
Uppdatera information om kamerastyrenhetens tillstånd
Nu utför vi våra beräkningar som konverterar pekarkoordinatinformationen som spåras i m_panPointerPosition till ny koordinatinformation respektive vårt 3D-scenutrymme. Vår app anropar den här metoden varje gång vi uppdaterar huvudappsloopen. I den beräknar vi den nya positionsinformation som vi vill skicka till appen som används för att uppdatera vymatrisen före projektion till visningsplatsen.
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 );
}
Eftersom vi inte vill att touch- eller mus jitter ska göra vår kamera panorering ryckig, ställer vi in en död zon runt pekaren med en diameter på 32 bildpunkter. Vi har också ett hastighetsvärde, som i det här fallet är 1:1 med pekarens pixelbläddering förbi den döda zonen. Du kan justera det här beteendet för att sakta ned eller påskynda rörelsehastigheten.
Uppdatera visningsmatrisen med den nya kamerapositionen
Nu kan vi få en scenrymdkoordinat som kameran fokuserar på och som uppdateras när du uppmanar din app att göra det (till exempel var 60:e sekund i huvudappsloopen). Det här pseudokoden föreslår det anropsbeteende som du kan implementera:
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.
);
Grattis! Du har implementerat en enkel uppsättning kamerapanoreringskontroller i ditt spel.