Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
UwP-games (Universal Windows Platform) worden uitgevoerd op een groot aantal verschillende apparaten, zoals desktopcomputers, laptops en tablets. Een apparaat kan een overvloed aan invoer- en controlemechanismen hebben. In dit document worden de belangrijkste procedures beschreven waarmee u rekening moet houden wanneer u met invoerapparaten werkt en ziet u hoe Marble Maze deze procedures toepast.
Opmerking
De voorbeeldcode die overeenkomt met dit document vindt u in het DirectX Marble Maze-gamevoorbeeld.
Hier volgen enkele van de belangrijkste punten die in dit document worden besproken wanneer u met invoer in uw game werkt:
Indien mogelijk ondersteunt u meerdere invoerapparaten om uw game in staat te stellen een breder scala aan voorkeuren en mogelijkheden onder uw klanten aan te bieden. Hoewel gamecontroller en sensorgebruik optioneel is, raden we het ten zeerste aan om de spelerervaring te verbeteren. We hebben de gamecontroller- en sensor-API's ontworpen om u te helpen deze invoerapparaten gemakkelijker te integreren.
Als u aanraking wilt initialiseren, moet u zich registreren voor venster-gebeurtenissen, zoals wanneer de aanwijzer is geactiveerd, vrijgegeven en verplaatst. Als u de versnellingsmeter wilt initialiseren, maakt u een Windows::Devices::Sensors::Accelerometer-object wanneer u de toepassing initialiseert. Voor een gamecontroller is geen initialisatie vereist.
Voor games met één speler kunt u overwegen of invoer van alle mogelijke controllers moet worden gecombineerd. Op deze manier hoeft u niet bij te houden welke invoer afkomstig is van welke controller. U kunt ook alleen invoer bijhouden van de laatst toegevoegde controller, zoals we in dit voorbeeld doen.
Windows-gebeurtenissen verwerken voordat u invoerapparaten verwerkt.
Gamecontroller en versnellingsmeter ondersteunen polling. Dat wil gezegd, u kunt gegevens peilen wanneer u deze nodig hebt. Voor touch-gebruik, leg aanraakgebeurtenissen vast in gegevensstructuren die beschikbaar zijn voor de invoerverwerkingscode.
Overweeg of invoerwaarden moeten worden genormaliseerd in een gemeenschappelijke indeling. Als u dit doet, kunt u vereenvoudigen hoe invoer wordt geïnterpreteerd door andere onderdelen van uw game, zoals fysicasimulatie, en kunt u eenvoudiger games schrijven die op verschillende schermresoluties werken.
Invoerapparaten die worden ondersteund door Marble Maze
Marble Maze ondersteunt de gamecontroller, muis en aanraken om menu-items te selecteren, en de gamecontroller, muis, aanraken en de accelerometer om spelspel te regelen. Marble Maze maakt gebruik van de Windows::Gaming::Input API's om de controller voor invoer te peilen. Met Touch kunnen toepassingen aanraking bijhouden en erop reageren. Een versnellingsmeter is een sensor die de kracht meet die langs de X-, Y- en Z-assen wordt toegepast. Met behulp van Windows Runtime kunt u de huidige status van het versnellingsmeterapparaat peilen en aanraakgebeurtenissen ontvangen via het windows Runtime-mechanisme voor gebeurtenisafhandeling.
Opmerking
In dit document wordt gebruikgemaakt van aanraken om te verwijzen naar aanraak- en muisinvoer en muisaanwijzer om te verwijzen naar elk apparaat dat gebruikmaakt van aanwijzers. Omdat aanraken en de muis standaardaanwijzers gebruiken, kunt u een van beide apparaten gebruiken om menu-items te selecteren en gamespel te beheren.
Opmerking
Het pakketmanifest stelt Landscape in als de enige ondersteunde rotatie voor het spel om te voorkomen dat de oriëntatie verandert wanneer u het apparaat draait om het knikkertje te rollen. Als u het pakketmanifest wilt weergeven, opent u Package.appxmanifest in de Solution Explorer- in Visual Studio.
Invoerapparaten initialiseren
De gamecontroller vereist geen initialisatie. Als u aanraking wilt initialiseren, moet u zich registreren voor venster-gebeurtenissen, zoals wanneer de aanwijzer is geactiveerd (bijvoorbeeld wanneer de speler op de muisknop drukt of het scherm aanraakt), wordt vrijgegeven en verplaatst. Als u de versnellingsmeter wilt initialiseren, moet u een Windows::D evices::Sensors::Accelerometer object maken wanneer u de toepassing initialiseert.
In het volgende voorbeeld ziet u hoe de methode App::SetWindow zich registreert voor de Windows::UI::Core::CoreWindow::PointerPressed-, Windows::UI::Core::CoreWindow::PointerReleaseden Windows::UI::Core::CoreWindow::PointerMoved pointer events. Deze gebeurtenissen worden geregistreerd tijdens de initialisatie van de toepassing en vóór de gamelus.
Deze gebeurtenissen worden verwerkt in een afzonderlijke thread die de event handlers aanroept.
Zie Marble Maze-toepassingsstructuurvoor meer informatie over hoe de toepassing wordt geïnitialiseerd.
window->PointerPressed += ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(
this,
&App::OnPointerPressed);
window->PointerReleased += ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(
this,
&App::OnPointerReleased);
window->PointerMoved += ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(
this,
&App::OnPointerMoved);
De klasse MarbleMazeMain maakt ook een std::map--object om aanraakgebeurtenissen vast te houden. De sleutel voor dit kaartobject is een waarde die de invoerpointer uniek identificeert. Elke toets wordt toegewezen aan de afstand tussen elk aanraakpunt en het midden van het scherm. Marble Maze gebruikt deze waarden later om de hoeveelheid te berekenen waarmee het doolhof wordt gekanteld.
typedef std::map<int, XMFLOAT2> TouchMap;
TouchMap m_touches;
De klasse MarbleMazeMain bevat ook een Accelerometer object.
Windows::Devices::Sensors::Accelerometer^ m_accelerometer;
Het Accelerometer object wordt geïnitialiseerd in de MarbleMazeMain constructor, zoals wordt weergegeven in het volgende voorbeeld. De methode Windows::Devices::Sensors::Accelerometer::GetDefault geeft een exemplaar van de standaard accelerometer terug. Als er geen standaard accelerometer is, retourneert Accelerometer::GetDefaultnullptr.
// Returns accelerometer ref if there is one; nullptr otherwise.
m_accelerometer = Windows::Devices::Sensors::Accelerometer::GetDefault();
Navigeren in de menu's
U kunt de muis, aanraking of een gamecontroller gebruiken om als volgt door de menu's te navigeren:
- Gebruik het directionele pad om het actieve menu-item te wijzigen.
- Gebruik aanraken, de knop A of de menuknop om een menu-item te kiezen of het huidige menu te sluiten, zoals de tabel met hoge score.
- Gebruik de menuknop om de game te onderbreken of te hervatten.
- Klik op een menu-item met de muis om die actie te kiezen.
Invoer van gamecontroller bijhouden
Als u de gamepads wilt bijhouden die momenteel zijn verbonden met het apparaat, definieert MarbleMazeMain een lidvariabele, m_myGamepads, een verzameling Windows::Gaming::Input::Gamepad-objecten. Dit wordt als volgt geïnitialiseerd in de constructor:
m_myGamepads = ref new Vector<Gamepad^>();
for (auto gamepad : Gamepad::Gamepads)
{
m_myGamepads->Append(gamepad);
}
Daarnaast registreert de MarbleMazeMain constructor gebeurtenissen voor wanneer gamepads worden toegevoegd of verwijderd:
Gamepad::GamepadAdded +=
ref new EventHandler<Gamepad^>([=](Platform::Object^, Gamepad^ args)
{
m_myGamepads->Append(args);
m_currentGamepadNeedsRefresh = true;
});
Gamepad::GamepadRemoved +=
ref new EventHandler<Gamepad ^>([=](Platform::Object^, Gamepad^ args)
{
unsigned int indexRemoved;
if (m_myGamepads->IndexOf(args, &indexRemoved))
{
m_myGamepads->RemoveAt(indexRemoved);
m_currentGamepadNeedsRefresh = true;
}
});
Wanneer een gamepad wordt toegevoegd, wordt deze toegevoegd aan m_myGamepads; wanneer een gamepad wordt verwijderd, controleren we of de gamepad zich in m_myGamepadsbevindt en als dat het is, verwijderen we het. In beide gevallen stellen we m_currentGamepadNeedsRefresh in op true, wat aangeeft dat we m_gamepadopnieuw moeten toewijzen.
Ten slotte wijzen we een gamepad toe aan m_gamepad en stellen we m_currentGamepadNeedsRefresh in op valse:
m_gamepad = GetLastGamepad();
m_currentGamepadNeedsRefresh = false;
In de methode Update controleren we of m_gamepad opnieuw moet worden toegewezen:
if (m_currentGamepadNeedsRefresh)
{
auto mostRecentGamepad = GetLastGamepad();
if (m_gamepad != mostRecentGamepad)
{
m_gamepad = mostRecentGamepad;
}
m_currentGamepadNeedsRefresh = false;
}
Als m_gamepad opnieuw moet worden toegewezen, wijzen we er de meest recent toegevoegde gamepad aan toe met behulp van GetLastGamepad. Dit wordt als volgt gedefinieerd:
Gamepad^ MarbleMaze::MarbleMazeMain::GetLastGamepad()
{
Gamepad^ gamepad = nullptr;
if (m_myGamepads->Size > 0)
{
gamepad = m_myGamepads->GetAt(m_myGamepads->Size - 1);
}
return gamepad;
}
Deze methode retourneert gewoon de laatste gamepad in m_myGamepads.
U kunt maximaal vier gamecontrollers verbinden met een Windows 10-apparaat. Om te voorkomen dat u moet achterhalen welke controller de actieve controller is, volgen we alleen de laatst toegevoegde gamepad. Als uw game meer dan één speler ondersteunt, moet u invoer voor elke speler afzonderlijk bijhouden.
De methode MarbleMazeMain::Update controleert de gamepad om invoer te verkrijgen:
if (m_gamepad != nullptr)
{
m_oldReading = m_newReading;
m_newReading = m_gamepad->GetCurrentReading();
}
We houden de invoerwaarde bij die we in het laatste frame hebben gekregen met m_oldReading, en de nieuwste invoerwaarde met m_newReading, die we krijgen door Gamepad::GetCurrentReadingop te roepen. Hiermee wordt een GamepadReading--object geretourneerd, dat informatie bevat over de huidige status van de gamepad.
Om te controleren of een knop zojuist is ingedrukt of vrijgegeven, definiëren we MarbleMazeMain::ButtonJustPressed en MarbleMazeMain::ButtonJustReleased, waarmee knopleesingen uit dit frame en het laatste frame worden vergeleken. Op deze manier kunnen we alleen een actie uitvoeren op het moment dat een knop in eerste instantie wordt ingedrukt of losgelaten, en niet wanneer deze wordt vastgehouden:
bool MarbleMaze::MarbleMazeMain::ButtonJustPressed(GamepadButtons selection)
{
bool newSelectionPressed = (selection == (m_newReading.Buttons & selection));
bool oldSelectionPressed = (selection == (m_oldReading.Buttons & selection));
return newSelectionPressed && !oldSelectionPressed;
}
bool MarbleMaze::MarbleMazeMain::ButtonJustReleased(GamepadButtons selection)
{
bool newSelectionReleased =
(GamepadButtons::None == (m_newReading.Buttons & selection));
bool oldSelectionReleased =
(GamepadButtons::None == (m_oldReading.Buttons & selection));
return newSelectionReleased && !oldSelectionReleased;
}
GamepadButtons-metingen worden vergeleken met bitgewijze bewerkingen. We controleren of een knop wordt ingedrukt met bitwise en (&). We bepalen of een knop net is ingedrukt of losgelaten door het oude lezen en de nieuwe lezing te vergelijken.
Met behulp van de bovenstaande methoden controleren we of bepaalde knoppen zijn ingedrukt en voeren we eventuele bijbehorende acties uit die moeten plaatsvinden. Wanneer bijvoorbeeld de menuknop (GamepadButtons::Menu) wordt ingedrukt, verandert de status van de game van actief in onderbroken of onderbroken naar actief.
if (ButtonJustPressed(GamepadButtons::Menu) || m_pauseKeyPressed)
{
m_pauseKeyPressed = false;
if (m_gameState == GameState::InGameActive)
{
SetGameState(GameState::InGamePaused);
}
else if (m_gameState == GameState::InGamePaused)
{
SetGameState(GameState::InGameActive);
}
}
We controleren ook of de speler op de knop Beeld drukt, in welk geval we het spel opnieuw starten of de tabel met hoge score wissen:
if (ButtonJustPressed(GamepadButtons::View) || m_homeKeyPressed)
{
m_homeKeyPressed = false;
if (m_gameState == GameState::InGameActive ||
m_gameState == GameState::InGamePaused ||
m_gameState == GameState::PreGameCountdown)
{
SetGameState(GameState::MainMenu);
m_inGameStopwatchTimer.SetVisible(false);
m_preGameCountdownTimer.SetVisible(false);
}
else if (m_gameState == GameState::HighScoreDisplay)
{
m_highScoreTable.Reset();
}
}
Als het hoofdmenu actief is, verandert de actieve menuopdracht wanneer het directionele pad omhoog of omlaag wordt ingedrukt. Als de gebruiker de huidige selectie kiest, wordt het juiste UI-element gemarkeerd als gekozen.
// Handle menu navigation.
bool chooseSelection =
(ButtonJustPressed(GamepadButtons::A)
|| ButtonJustPressed(GamepadButtons::Menu));
bool moveUp = ButtonJustPressed(GamepadButtons::DPadUp);
bool moveDown = ButtonJustPressed(GamepadButtons::DPadDown);
switch (m_gameState)
{
case GameState::MainMenu:
if (chooseSelection)
{
m_audio.PlaySoundEffect(MenuSelectedEvent);
if (m_startGameButton.GetSelected())
{
m_startGameButton.SetPressed(true);
}
if (m_highScoreButton.GetSelected())
{
m_highScoreButton.SetPressed(true);
}
}
if (moveUp || moveDown)
{
m_startGameButton.SetSelected(!m_startGameButton.GetSelected());
m_highScoreButton.SetSelected(!m_startGameButton.GetSelected());
m_audio.PlaySoundEffect(MenuChangeEvent);
}
break;
case GameState::HighScoreDisplay:
if (chooseSelection || anyPoints)
{
SetGameState(GameState::MainMenu);
}
break;
case GameState::PostGameResults:
if (chooseSelection || anyPoints)
{
SetGameState(GameState::HighScoreDisplay);
}
break;
case GameState::InGamePaused:
if (m_pausedText.IsPressed())
{
m_pausedText.SetPressed(false);
SetGameState(GameState::InGameActive);
}
break;
}
Aanraak- en muisinvoer bijhouden
Voor aanraak- en muisinvoer wordt een menu-item gekozen wanneer de gebruiker deze aanraakt of klikt. In het volgende voorbeeld ziet u hoe de MarbleMazeMain::Update methode aanwijzerinvoer verwerkt om menu-items te selecteren. De lidvariabele m_pointQueue houdt de locaties bij waar de gebruiker het scherm heeft aangeraakt of aangeklikt. Hoe Marble Maze wijzerinvoer verzamelt, wordt verderop in dit document in de sectie verwerking van wijzerinvoerbeschreven.
// Check whether the user chose a button from the UI.
bool anyPoints = !m_pointQueue.empty();
while (!m_pointQueue.empty())
{
UserInterface::GetInstance().HitTest(m_pointQueue.front());
m_pointQueue.pop();
}
De methode UserInterface::HitTest bepaalt of het opgegeven punt zich in de grenzen van een UI-element bevindt. Alle UI-elementen die aan deze test voldoen, worden gemarkeerd als aangeraakt. Deze methode gebruikt de helperfunctie PointInRect om te bepalen of het opgegeven punt zich in de grenzen van elk UI-element bevindt.
void UserInterface::HitTest(D2D1_POINT_2F point)
{
for (auto iter = m_elements.begin(); iter != m_elements.end(); ++iter)
{
if (!(*iter)->IsVisible())
continue;
TextButton* textButton = dynamic_cast<TextButton*>(*iter);
if (textButton != nullptr)
{
D2D1_RECT_F bounds = (*iter)->GetBounds();
textButton->SetPressed(PointInRect(point, bounds));
}
}
}
De gamestatus bijwerken
Nadat de MarbleMazeMain::Update methode controller en aanraakinvoer verwerkt, wordt de gamestatus bijgewerkt als er op een knop is gedrukt.
// Update the game state if the user chose a menu option.
if (m_startGameButton.IsPressed())
{
SetGameState(GameState::PreGameCountdown);
m_startGameButton.SetPressed(false);
}
if (m_highScoreButton.IsPressed())
{
SetGameState(GameState::HighScoreDisplay);
m_highScoreButton.SetPressed(false);
}
Gamespel beheren
De gamelus en de MarbleMazeMain::Update methode werken samen om de status van gameobjecten bij te werken. Als uw game invoer van meerdere apparaten accepteert, kunt u de invoer van alle apparaten verzamelen in één set variabelen, zodat u code kunt schrijven die gemakkelijker te onderhouden is. De methode MarbleMazeMain::Update definieert één set variabelen waarmee beweging van alle apparaten wordt verzameld.
float combinedTiltX = 0.0f;
float combinedTiltY = 0.0f;
Het invoermechanisme kan variëren van het ene invoerapparaat naar het andere. Aanwijzerinvoer wordt bijvoorbeeld verwerkt met behulp van het Windows Runtime-gebeurtenisafhandelingsmodel. Daarentegen peilt u naar invoergegevens van de gamecontroller wanneer u deze nodig hebt. U wordt aangeraden altijd het invoermechanisme te volgen dat is voorgeschreven voor een bepaald apparaat. In deze sectie wordt beschreven hoe Marble Maze invoer leest van elk apparaat, hoe deze de gecombineerde invoerwaarden bijwerkt en hoe de gecombineerde invoerwaarden worden gebruikt om de status van het spel bij te werken.
Invoer van aanwijzer verwerken
Wanneer u met aanwijzerinvoer werkt, roept u de Windows::UI::Core::CoreDispatcher::P rocessEvents methode aan om venster-gebeurtenissen te verwerken. Roep deze methode aan in uw gamelus voordat u de scène bijwerkt of weergeeft. Marble Maze roept dit aan in de methode App::Run:
while (!m_windowClosed)
{
if (m_windowVisible)
{
CoreWindow::GetForCurrentThread()->
Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
m_main->Update();
if (m_main->Render())
{
m_deviceResources->Present();
}
}
else
{
CoreWindow::GetForCurrentThread()->
Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
}
Als het venster zichtbaar is, geven we CoreProcessEventsOption::P rocessAllIfPresent door aan ProcessEvents om alle gebeurtenissen in de wachtrij te verwerken en onmiddellijk terug te keren; anders geven we CoreProcessEventsOption::P rocessOneAndAllPending door om alle gebeurtenissen in de wachtrij te verwerken en te wachten op de volgende nieuwe gebeurtenis. Nadat gebeurtenissen zijn verwerkt, rendert Marble Maze en presenteert het het volgende frame.
De Windows Runtime roept de geregistreerde handler aan voor elke gebeurtenis die heeft plaatsgevonden. De methode App::SetWindow registreert voor gebeurtenissen en stuurt aanwijzergegevens door naar de klasse MarbleMazeMain.
void App::OnPointerPressed(
Windows::UI::Core::CoreWindow^ sender,
Windows::UI::Core::PointerEventArgs^ args)
{
m_main->AddTouch(args->CurrentPoint->PointerId, args->CurrentPoint->Position);
}
void App::OnPointerReleased(
Windows::UI::Core::CoreWindow^ sender,
Windows::UI::Core::PointerEventArgs^ args)
{
m_main->RemoveTouch(args->CurrentPoint->PointerId);
}
void App::OnPointerMoved(
Windows::UI::Core::CoreWindow^ sender,
Windows::UI::Core::PointerEventArgs^ args)
{
m_main->UpdateTouch(args->CurrentPoint->PointerId, args->CurrentPoint->Position);
}
De klasse MarbleMazeMain reageert op aanwijzers door het kaartobject bij te werken dat touch-gebeurtenissen bevat. De methode MarbleMazeMain::AddTouch wordt aangeroepen wanneer de aanwijzer voor het eerst wordt ingedrukt, bijvoorbeeld wanneer de gebruiker het scherm in eerste instantie op een apparaat met aanraakscherm aanraakt. De methode MarbleMazeMain::UpdateTouch wordt aangeroepen wanneer de aanwijzerpositie wordt verplaatst. De methode MarbleMazeMain::RemoveTouch wordt aangeroepen wanneer de aanwijzer wordt vrijgegeven, bijvoorbeeld wanneer de gebruiker stopt met het aanraken van het scherm.
void MarbleMazeMain::AddTouch(int id, Windows::Foundation::Point point)
{
m_touches[id] = PointToTouch(point, m_deviceResources->GetLogicalSize());
m_pointQueue.push(D2D1::Point2F(point.X, point.Y));
}
void MarbleMazeMain::UpdateTouch(int id, Windows::Foundation::Point point)
{
if (m_touches.find(id) != m_touches.end())
m_touches[id] = PointToTouch(point, m_deviceResources->GetLogicalSize());
}
void MarbleMazeMain::RemoveTouch(int id)
{
m_touches.erase(id);
}
De functie PointToTouch vertaalt de huidige positie van de aanwijzer zodat de oorsprong zich in het midden van het scherm bevindt en schaalt vervolgens de coördinaten zodanig dat ze ongeveer tussen -1.0 en +1.0 liggen. Dit maakt het gemakkelijker om de kanteling van het doolhof op een consistente manier over verschillende invoermethoden te berekenen.
inline XMFLOAT2 PointToTouch(Windows::Foundation::Point point, Windows::Foundation::Size bounds)
{
float touchRadius = min(bounds.Width, bounds.Height);
float dx = (point.X - (bounds.Width / 2.0f)) / touchRadius;
float dy = ((bounds.Height / 2.0f) - point.Y) / touchRadius;
return XMFLOAT2(dx, dy);
}
De methode MarbleMazeMain::Update werkt de gecombineerde invoerwaarden bij door de kantelingsfactor te verhogen met een constante schaalwaarde. Deze schaalwaarde is bepaald door te experimenteren met verschillende waarden.
// Account for touch input.
for (TouchMap::const_iterator iter = m_touches.cbegin();
iter != m_touches.cend();
++iter)
{
combinedTiltX += iter->second.x * m_touchScaleFactor;
combinedTiltY += iter->second.y * m_touchScaleFactor;
}
Accelerometerinvoer verwerken
Voor het verwerken van accelerometerinvoer roept de methode MarbleMazeMain::Update de Windows::Devices::Sensors::Accelerometer::GetCurrentReading aan. Deze methode retourneert een Windows::Devices::Sensors::AccelerometerReading object, dat een versnellingsmetermeting vertegenwoordigt. De Windows::Devices::Sensors::AccelerometerReading::AccelerationX en Windows::Devices::Sensors::AccelerometerReading::AccelerationY bevatten respectievelijk de g-force versnelling langs de X- en Y-as.
In het volgende voorbeeld ziet u hoe de methode MarbleMazeMain::Update de versnellingsmeter peilt en de gecombineerde invoerwaarden bijwerkt. Wanneer u het apparaat kantelt, zorgt de zwaartekracht ervoor dat het marmer sneller beweegt.
// Account for sensors.
if (m_accelerometer != nullptr)
{
Windows::Devices::Sensors::AccelerometerReading^ reading =
m_accelerometer->GetCurrentReading();
if (reading != nullptr)
{
combinedTiltX +=
static_cast<float>(reading->AccelerationX) * m_accelerometerScaleFactor;
combinedTiltY +=
static_cast<float>(reading->AccelerationY) * m_accelerometerScaleFactor;
}
}
Omdat u niet zeker weet dat er een versnellingsmeter aanwezig is op de computer van de gebruiker, moet u er altijd voor zorgen dat u een geldige Accelerometer object hebt voordat u de versnellingsmeter peilt.
Invoer van gamecontroller verwerken
In de methode MarbleMazeMain::Update gebruiken we m_newReading om invoer van de linker analoge stick te verwerken:
float leftStickX = static_cast<float>(m_newReading.LeftThumbstickX);
float leftStickY = static_cast<float>(m_newReading.LeftThumbstickY);
auto oppositeSquared = leftStickY * leftStickY;
auto adjacentSquared = leftStickX * leftStickX;
if ((oppositeSquared + adjacentSquared) > m_deadzoneSquared)
{
combinedTiltX += leftStickX * m_controllerScaleFactor;
combinedTiltY += leftStickY * m_controllerScaleFactor;
}
We controleren of de invoer van de linker analoge stick zich buiten de dode zone bevindt, en als dat het geval is, voegen we deze toe aan gecombineerdeTiltX en gecombineerdeTiltY (vermenigvuldigd met een schaalfactor) om het platform te kantelen.
Belangrijk
Wanneer u met een gamecontroller werkt, moet u altijd rekening houden met de dode zone. De dode zone verwijst naar de variantie tussen gamepads in hun gevoeligheid voor de eerste beweging. In sommige controllers kan een kleine beweging geen leesbewerking genereren, maar in andere controllers kan het een meetbare lezing genereren. Maak hiervoor een zone van niet-beweging voor de eerste duimstickbeweging. Voor meer informatie over de dode zone, zie De duimsticks lezen.
Invoer toepassen op de gamestatus
Apparaten rapporteren invoerwaarden op verschillende manieren. De invoer van de aanwijzer bevindt zich bijvoorbeeld in schermcoördinaten en controllerinvoer heeft mogelijk een totaal andere indeling. Een uitdaging met het combineren van invoer van meerdere apparaten in één set invoerwaarden is normalisatie of het converteren van waarden naar een gemeenschappelijke indeling. Marble Maze normaliseert waarden door ze te schalen naar het bereik [-1.0, 1.0]. De functie PointToTouch, die eerder in deze sectie is beschreven, converteert schermcoördinaten naar genormaliseerde waarden die ongeveer tussen -1.0 en +1.0 liggen.
Aanbeveling
Zelfs als uw toepassing één invoermethode gebruikt, raden we u aan invoerwaarden altijd te normaliseren. Dit kan vereenvoudigen hoe invoer wordt geïnterpreteerd door andere onderdelen van uw game, zoals fysicasimulatie, en maakt het eenvoudiger om games te schrijven die werken op verschillende schermresoluties.
Nadat de MarbleMazeMain::Update methode input verwerkt, wordt er een vector gemaakt die het effect van de kanteling van het doolhof op het marmer vertegenwoordigt. In het volgende voorbeeld ziet u hoe Marble Maze de XMVector3Normalize functie gebruikt om een genormaliseerde zwaartekrachtvector te maken. De maxTilt variabele beperkt de mate waarin het doolhof kantelt en voorkomt dat het doolhof op zijn zij kantelt.
const float maxTilt = 1.0f / 8.0f;
XMVECTOR gravity = XMVectorSet(
combinedTiltX * maxTilt,
combinedTiltY * maxTilt,
1.0f,
0.0f);
gravity = XMVector3Normalize(gravity);
Om de update van scèneobjecten te voltooien, geeft Marble Maze de bijgewerkte zwaartekrachtvector door aan de fysicasimulatie, werkt de fysicasimulatie bij voor de tijd die is verstreken sinds het vorige frame en werkt de positie en stand van het marmer bij. Als het marmer door het doolhof is gevallen, plaatst de methode MarbleMazeMain::Update methode het marmer terug bij het laatste controlepunt dat het marmer heeft aangeraakt en de status van de fysicasimulatie opnieuw instelt.
XMFLOAT3A g;
XMStoreFloat3(&g, gravity);
m_physics.SetGravity(g);
if (m_gameState == GameState::InGameActive)
{
// Only update physics when gameplay is active.
m_physics.UpdatePhysicsSimulation(static_cast<float>(m_timer.GetElapsedSeconds()));
// ...Code omitted for simplicity...
}
// ...Code omitted for simplicity...
// Check whether the marble fell off of the maze.
const float fadeOutDepth = 0.0f;
const float resetDepth = 80.0f;
if (marblePosition.z >= fadeOutDepth)
{
m_targetLightStrength = 0.0f;
}
if (marblePosition.z >= resetDepth)
{
// Reset marble.
memcpy(&marblePosition, &m_checkpoints[m_currentCheckpoint], sizeof(XMFLOAT3));
oldMarblePosition = marblePosition;
m_physics.SetPosition((const XMFLOAT3&)marblePosition);
m_physics.SetVelocity(XMFLOAT3(0, 0, 0));
m_lightStrength = 0.0f;
m_targetLightStrength = 1.0f;
m_resetCamera = true;
m_resetMarbleRotation = true;
m_audio.PlaySoundEffect(FallingEvent);
}
In deze sectie wordt niet beschreven hoe de fysicasimulatie werkt. Zie Physics.h en Physics.cpp in de marble maze-bronnen voor meer informatie hierover.
Volgende stappen
Lees Audio toevoegen aan het Marble Maze-voorbeeld voor informatie over enkele van de belangrijkste procedures waarmee u rekening moet houden wanneer u met audio werkt. In het document wordt beschreven hoe Marble Maze gebruikmaakt van Microsoft Media Foundation en XAudio2 om audiobronnen te laden, te mixen en af te spelen.
Verwante onderwerpen
- Audio toevoegen aan het Marble Maze-voorbeeld
- Visuele inhoud toevoegen aan het Marble Maze-voorbeeld
- Developing Marble Maze, een UWP-spel in C++ en DirectX