• Keine Ergebnisse gefunden

Kapitel 3. DirectInput directx mit visual basic programmieren

N/A
N/A
Protected

Academic year: 2022

Aktie "Kapitel 3. DirectInput directx mit visual basic programmieren"

Copied!
30
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Kapitel 3

DirectInput

3.1 Objekthierarchie 254

3.2 Cooperative Level 257

3.3 Datenformat 258

3.4 Beispiel: Tastatur 260

3.5 Beispiel: Joystick 262

3.6 Beispiel: Maus 268

3.7 Beispiel: DirectInput und Direct3D 272

3.8 Bewegung im 3D-Raum 279

(2)

Objekthierarchie 254

DirectInput (DI) ist eine API für Eingabegeräte. Durch die Bereitstellung allge- meiner Device Interfaces bietet DirectInput die Sicherheit, auch in der Zukunft auf eine Vielzahl von Geräten zugreifen zu können, deren technische Möglichkei- ten heute noch nicht definiert sind. DirectInput unterscheidet drei Typen von I/O- Geräten.

Standard-System-Tastatur

Maus oder mausähnliche Geräte (Maus, Trackball, Touchpad ...)

Joysticks bzw alle übrigen Geräte (Joystick, Gamepad, Lenkräder...)

Die normale Windows API bietet eine Reihe von unterstüzenden Methoden zur Steuerung von I/O-Geräten, dennoch werden diese durch DirectInput ersetzt. Dies hat zum einen den Grund, dass mit DI eine freie (für die Zukunft offene) Schnitt- stelle geschaffen wurde, zum anderen wurde die Geschwindigkeit der bestehen- den Technik problematisch. Der Grundkonzeption von DirectX entsprechend, wurde auch bei den Eingabegeräten Wert auf hohe Performance gelegt. Natürlich finden wir auch bei DI einen direkten Zugriff auf die Hardware. Dabei wird das übliche Nachrichtensystem von Windows ignoriert. Dies garantiert quasi eine schnelle Reaktionszeit. Das Verhalten von DirectInput ist vom Programmierer konfigurierbar. Je nach Einsatzzweck wird er unterschiedliche Konfigurationen festlegen.

3.1 Objekthierarchie

DirectInput Interface

Das DirectInput Interface stellt die erste Verbindung zum I/O Gerät her. Es dient zur Konfiguration und Initialisierung.

Devices

Mit DirectInput Device werden die Ein- / Ausgabegeräte bezeichnet. Diese Objekte (Maus, Tastatur, Joystick...) bestehen aus verschiedenen Objekten.

Objekte

Objekte sind die Bestandteile eines Devices. Objekte können Tasten, Knöpfe, Achsen, Drehräder ... sein.

Effekte

Neben den Objekten existieren noch die Effekte. Effekte finden vor allem bei neueren Geräten Verwendung. Insbesondere sei der Force Feedback Joystick genannt.

Die verschiedenen Bestandteile der DirectInput Architekture erfassen im Regel- fall Daten. Dabei ist es ohne Bedeutung, wie die Daten erfasst wurden. Ob eine Maus die Koordinaten mechanisch per Kugel und Zahnrad oder optisch an Direc- tInput weiterleitet spielt keine Rolle. Betrachten wir die Architektur an einem Beispiel, so würden wir eine einfache Maus folgendermaßen skizzieren.

(3)

Device → Maus

Objekte → zwei Tasten

zwei Achsen (X- und Y-Achse)

Effekte → keine

Auflisten der verfügbaren Geräte und Objekte

Anhand eines Beispielprogramms werden wir demonstrieren, wie Sie Informatio- nen über die angeschlossene Inputhardware sammeln. Diese Informationen bilden die Grundlage für alle späteren Aktionen. Anders als bei Direct3D oder Direct- Draw können die Inputgeräte von DirectX nicht simuliert werden.

Unser Beispielprogramm erkennt alle eingetragenen I/O-Geräte. Die Geräte müs- sen nicht angeschlossen sein, es reicht wenn die Geräte von Windows als I/O- Geräte registriert wurden. So können Sie z.B. über die Systemsteuerung/Game- controller weitere Joysticks eintragen. Diese werden dann ebenfalls mit aufgelis- tet.

Beginnen wir mit den Dimensionierungen.

Dim dx As New DirectX7 Dim di As DirectInput

Dim diDEV As DirectInputDevice

Dim diEnumDev As DirectInputEnumDevices Dim diEnumOBJ As DirectInputEnumDeviceObjects

Um auf die Geräteliste sowie auf die Objektliste zugreifen zu können, benötigen wir die Variablen vom Typ DirectInputEnumDevices und DirectInputEnum DeviceObjects. Diese werden die gewünschten Informationen beinhalten.

Wir beginnen mit der Form_Load()-Subroutine.

Bild 3.1: Objekthierarchie

(4)

Objekthierarchie 256

Private Sub Form_Load()

Set di = dx.DirectInputCreate()

Zuerst benötigen wir das DirectInput-Objekt. Dieses erzeugen wir mit der DirectX7.DirectInputCreate() Methode. Diese Methode besitzt keine Parameter.

Set diEnumDev = di.GetDIEnumDevices(0 , DIEDFL_INCLUDEPHANTOMS)

Mit der DirectInput.GetDiEnumDevices() Methode weisen wir das DirectInput EnumDevices Objekt zu. Der erste Parameter ist vom Typ CONST_DIDEVICE TYPE, der zweite Parameter ist ein Flag aus der CONST_DIENUMDEVICES FLAGS Konstantenliste. Indem wir den ersten Parameter einfach auf 0 setzten, werden uns später alle Geräte (Maus, Tastatur, Joystick ...) aufgelistet werden.

Das Flag DIEDFL_INCLUDEPHANTOMS des zweiten Parameters sorgt dafür, dass auch die Geräte aufglistet werden, welche zurzeit nicht angeschlossen sind.

Bild 3.2: Geräteliste

(5)

DeviceCount = diEnumDev.GetCount() For i = 1 To DeviceCount

Set diDEV = _

di.CreateDevice(diEnumDev.GetItem(i).GetGuidInstance) Combo1.AddItem (diEnumDev.GetItem(i).GetProductName)

Der Reihe nach werden alle gefundenen Geräte mit der DirectInput.Create Device()-Methode erzeugt und die Namen der Geräte ausgelesen.

Next i

Combo1.Text = Combo1.List(0) Listen 1

End Sub

Mit der Subroutine Listen() aktualisieren wir die Listboxen auf Form1. Wie- derum zusätzlich zu dem Device erzeugen wir noch das DirectInput-Objekt. In diesem Objekt finden wir Informationen über das Gerät selber. Diese übertragen wir an die jeweiligen Listboxen.

Public Sub Listen(Index As Integer) List1.Clear

List2.Clear Set diDEV = _

di.CreateDevice(diEnumDev.GetItem(Index).GetGuidInstance) DeviceCount = diEnumDev.GetCount()

List1.AddItem "ProductName :" & _ (diEnumDev.GetItem(Index).GetProductName) List1.AddItem "InstanceName :" & _

(diEnumDev.GetItem(Index).GetInstanceName) List1.AddItem "GuidInstance :" & _

(diEnumDev.GetItem(Index).GetGuidInstance) List1.AddItem "GuidProduct :" & _

(diEnumDev.GetItem(Index).GetGuidProduct)

Set diEnumOBJ = diDEV.GetDeviceObjectsEnum(DIDFT_ALL) ObjectCount = diEnumOBJ.GetCount()

For u = 1 To ObjectCount

List2.AddItem (diEnumOBJ.GetItem(u).GetName) Next u

End Sub

3.2 Cooperative Level

Der Cooperative Level bestimmt, wie ein Gerät mit anderen Anwendungen oder dem Windowssystem geteilt wird. Für den Zugriff auf einzelnen I/O-Geräte ste- hen eine gewisse Zahl von Cooperative Levels zur Wahl. Die korrekte Festlegung des Cooperative Levels kann einige Probleme beim Umgang mit DirectX-Anwen- dungen in Windows vermeiden helfen.

(6)

Datenformat 258

Werden z.B. die I/O-Geräte nur abgefragt, wenn sich die Anwendung im Vorder- grund befindet, kann es passieren (falls die Anwendung den Fokus verliert), dass eine gestartete Aktion beim Loslassen einer Taste nicht beendet wird.

Die möglichen Cooperative Levels sind:

Die folgende Tabelle gibt an, welche Kombinationen für welche I/O-Geräte zuläs- sig sind.

Wenn eine Anwendung den exklusiven Zugriff auf die Tastatur erhält, unterdrückt DirectInput alle Tastaturnachrichten außer [Strg]+[Alt]+[Del] sowie [Alt)+ [ÿ].

3.3 Datenformat

Um gegenüber neuen Entwicklungen offen zu sein, bietet DirectInput eine sehr allgemeine Möglichkeit um auf die Hardware zuzugreifen. So existieren weitrei- chende Möglichkeiten zur Erstellung selbstdefinierter Datenformate. Für die nor- malen I/O-Geräte existieren bereits vordefinierte Datenformate. Diese können Sie der folgenden Tabelle entnehmen.

Cooperativ Level Kurzbeschreibung

DISCL_NONEXCLUSIVE Die Anwendung erhält den Zugriff auf das Gerät nicht exklusiv (zwingend für die Tastatur).

DISCL_EXCLUSIVE Andere Anwendungen können nicht exklusiv auf das Gerät zugreifen (zwingend für Force Feedback).

DISCL_FORDERGROUND Die Anwendung erhält nur Daten, wenn sie sich im Vor- dergrund befindet.

DISCL_BACKGROUND Die Anwendung erhält Daten im Vordergund und Hin- tergrund.

Cooperative Level Kurzbeschreibung

DISCL_NONEXCLUSIVE DISCL_BACKGROUND

alle Geräte ohne Force Feedback

→ Default DISCL_NONEXCLUSIVE

DISCL_FORDERGROUND

alle Geräte ohne Force Feedback

DISCL_EXCLUSIVE DISCL_FORDERGROUND

alle außer Tastatur

DISCL_EXCLUSIVE DISCL_BACKGROUND

Joysticks sowie Geräte mit Force Feedback

→ nicht zulässig für Tastatur und Maus

(7)

Die DirectInputDevice.SetCommonDataFormat()- und DirectInputDevice.Set- DateFormat()-Methoden teilen DirectInput mit, welche Objekte benutzt und wie die Daten empfangen werden.

3.3.1 Standard-Datenformat

Mit der DirectInputDevice.SetCommonDataFormat()-Methode können wir die Standard Datenformate festlegen. Die Methode beinhaltet nur einen Parameter.

Der Parameter format ist vom Typ CONST_DICOMMONDATAFORMATS.

Enum CONST_DICOMMONDATAFORMATS DIFORMAT_JOYSTICK = 3 DIFORMAT_JOYSTICK2 = 4 DIFORMAT_KEYBOARD = 1 DIFORMAT_MOUSE = 2 End Enum

Um das Datenformat z.B. für die Tastatur zu setzen, wählen Sie folgende Syntax:

DirectInputDevice.SetCommonDataFormat DIFORMAT_KEYBOARD

Bevor Sie auf ein Gerät zugreifen können, muss das Datenformat festgelegt wer- den. Während Sie auf das Gerät zugreifen, können Sie das Datenformat nicht ändern.

3.3.2 Benutzerdefiniertes Datenformat

Mit der DirectInputDevice.SetDataFormat()-Methode können Sie ein benutzer- definiertes Datenformat festlegen. Diese Methode beinhaltet zwei Parameter. Der erste Parameter format empfängt Daten über des Gerät selber. Der zweite Para- meter formatArray() ist für die Objekte des Gerätes reserviert.

Bevor wir die Methode aufrufen dürfen, müssen wir die Eigenschaften für die bei- den Parameter bestimmen. Das folgende Listing definiert das Datenformat für eine Maus mit zwei Achsen, allerdings ohne Knöpfe.

Datenformat Beschreibung

DIFORMAT_KEYBOARD Tastatur: Für jede Taste ein Byte. Wird eine Taste momentan gedrückt, so ist das oberste Bit des entspre- chenden Bytes gesetzt.

DIFORMAT_MOUSE Maus: vier Tasten, drei Achsen

DIFORMAT_JOYSTICK Joystick: <= 32 Knöpfe, <= 6 Achsen, <= 2 Schie- beregler, <= 4 Richtungsschalter

DIFORMAT_JOYSTICK2 Datenformat für erweiterte Joysticks

(8)

Beispiel: Tastatur 260

Dim dx As New DirectX7 Dim di As DirectInput

Dim diDev As DirectInputDevice Dim DataFormat As DIDATAFORMAT

Dim ObjektFormat(1) As DIOBJECTDATAFORMAT Private Sub Form_Load()

Set di = dx.DirectInputCreate()

Set did = di.CreateDevice("GUID_SysMouse") ObjektFormat (0).lFlags = DIDOI_POLLED ObjektFormat (0).lOfs = 0

ObjektFormat (0).lType = DIDFT_RELAXIS ObjektFormat (0).strGuid = "GUID_XAxis"

ObjektFormat (1).lFlags = DIDOI_POLLED ObjektFormat (1).lOfs = 4

ObjektFormat (1).lType = DIDFT_RELAXIS ObjektFormat (1).strGuid = "GUID_YAxis"

DataFormat.dataSize = 8

DataFormat.lFlags = DIDF_RELAXIS DataFormat.lObjSize = 4

DataFormat.numObjs = 2

diDev.SetDataFormat DataFormat, fDA() End Sub

3.4 Beispiel: Tastatur

Für die Eingabe über die Tastatur erstellen wir zuerst das DirectInput-Objekt.

Anschließend wird das DirectInput-Device erstellt, welches die Tastatur repräsen- tiert. Es bestimmt das Verhalten der Tastatur und empfängt die Daten, welche von der Tastatur gesendet werden.

Unser Beispielprogramm zeigt eine Listbox. In dieser werden die gedrückten Tas- ten angezeigt.

Schritt 1: Erstellen des DirectInput-Objektes und des Tastaturgerätes Schritt 2: Tastaturparameter setzen

Schritt 3: Verbindung zur Tastatur herstellen Schritt 4: Daten von der Tastatur empfangen

Für unser Beispielprogramm dimensionieren wir folgende Variablen.

Dim dx As New DirectX7 Dim di As DirectInput

Dim diDev As DirectInputDevice Dim TastaturStatus As DIKEYBOARDSTATE Dim Tasten(255) As String

Private Sub Form_Load()

(9)

Schritt 1: Erstellen des DirectInput-Objektes und des Tastaturgerätes Set di = dx.DirectInputCreate()

Set diDev = di.CreateDevice("GUID_SysKeyboard")

Schritt 2: Tastaturparameter setzen

Für das Standardgerät Tastatur können wir auf ein vordefiniertes Datenformat zugreifen. Deshalb benutzen wir die SetCommonDataFormat()-Methode mit dem Parameter DIFORMAT_KEYBOARD. Für Cooperative Level brauchen wir keinen exklusiven Zugriff (ist für die Tastatur auch nicht erlaubt), aber gleichzei- tig möchten wir die Tastaturdaten empfangen, auch wenn die Anwendung den Focus verliert.

diDev.SetCommonDataFormat DIFORMAT_KEYBOARD

diDev.SetCooperativeLevel Me.hWnd, DISCL_NONEXCLUSIVE Or _ DISCL_BACKGROUND

Schritt 3: Verbindung zur Tastatur herstellen

Die Methode Acquire() besitzt keine Parameter und erstellt die Verbindung zum Eingabegerät. Zu welchem Eingabegerät die Verbindung hergestellt werden soll, wird durch die DirectInput.CreateDevice()-Methode festgelegt.

diDev.Acquire

Timer1.Enabled = True End Sub

Bild 3.3: Bildschirmfoto Tastatur

(10)

Beispiel: Joystick 262

Schritt 4: Daten von der Tastatur empfangen

Über das Timerobjekt fragen wir die Tastaturdaten ab. Die DirectInput.Get DeviceStateKeyboard()-Methode empfängt unverzüglich die gewünschten Daten.

Private Sub Timer1_Timer() List1.Clear

diDev.GetDeviceStateKeyboard TastaturStatus For i = 0 To 255

If TastaturStatus.Key(i) <> 0 Then List1.AddItem KeyNames(i)

Die Funktion KeyNames() interpertiert den in TastaturStatus.Key() gespeicherten Rückgabewert. So erhalten wir eine aussagefähige Information auf dem Bild- schirm angezeigt.

End If Next End Sub

Interpretation der empfangenen Tastaturdaten:

Function KeyNames(ByVal iNum As Integer) As String Tasten(1) = "DIK_ESCAPE"

Tasten(2) = "DIK_1 On main keyboard"

Tasten(3) = "DIK_2 On main keyboard"

. . .

Tasten(220) = "DIK_RWIN Right Windows key"

Tasten(221) = "DIK_APPS Application key"

Tasten(116) = "DIK_PAUSE"

KeyNames = Tasten(iNum) End Function

3.5 Beispiel: Joystick

Bei dem Joystickdemo werden wir zuerst die angeschlossenen Joysticks abfragen.

Anschließend werden die Joystickfähigkeiten ermittelt und die notwendigen Para- meter gesetzt. Zum Abschluss werden die Joystickdaten empfangen.

Bei dem Tastaturdemo konnten wir voraussetzen, dass eine Tastatur am Computer angeschlossen ist. Die Annahme, das ein Joystick angeschlossen ist, können wir nicht treffen. Es ist deshalb notwendig abzufragen, welcher Joystick zur Zeit ver- fügbar ist. Gleichzeitig ist es wichtig, dass wir genaue Informationen über die Fähigkeiten des Eingabegerätes erhalten. Zu diesem Zeitpunkt wäre es verfrüht, wenn wir auf die vielfältigen Möglichkeiten des Force Feedback Joysticks einge- hen würden, deshalb werden wir diese etwas vernachlässigen.

(11)

Die Abfrage der Joystickdaten gestaltet sich komplizierter als bei dem Tastatur- demo. Die eintreffenden Daten per Timer-Objekt abzufragen wäre viel zu lang- sam. Der übliche Weg zum Empfangen von Joystickdaten ist es, eine Callback- Funktion einzurichten. Diese wird immer dann aufgerufen wenn neue Daten ein- treffen. Der Joystick liefert allerdings permanent Daten.

Schritt 1: Auflisten der verfügbaren Joysticks und Erzeugen des Joystick-Objek- tes

Schritt 2: Abfragen der Joystickfähigkeiten Schritt 3: Setzen der Joystickeigenschaften

Schritt 4: Direktes Empfangen der Joystickdaten per Callback-Funktion Für unser Beispielprogramm dimensionieren wir folgende Variablen:

Implements DirectXEvent

Da wir die Joystickdaten per Callback abrufen wollen, treffen wir mit der Imple- ments-Anweisung die Vorbereitung. DirectXEvent ist eine eigene Klasse. Sie beinhaltet nur eine Methode: DirectXEvent.DXCallback()

Dim dx As New DirectX7 Dim di As DirectInput

Dim diDev As DirectInputDevice

Dim diDevEnum As DirectInputEnumDevices Dim EventHandle As Long

Dim joyCaps As DIDEVCAPS Dim js As DIJOYSTATE Dim Achsen(8) As Boolean Bild 3.4: Bildschirmfoto Joystick

(12)

Beispiel: Joystick 264

Dim Knöpfe(32) As Boolean Dim Pov(4) As Boolean Dim JoyGuid(16) As String Dim Fd As DIDATAFORMAT

Dim fda(1) As DIOBJECTDATAFORMAT Dim Running As Boolean

Dim JoyAngeschlossen As Boolean

Schritt 1: Auflisten der verfügbaren Joysticks und Erzeugen des Joystick- Objektes

Mit diesem Beispielprogramm führen wir die Subroutine InitDirectInput() ein.

Sie wird jetzt und in Zukunft die Initialisierungsaufgaben übernehmen. Gleichzei- tig werden wir dieser Routine diverse Prüfungsaufgen anvertrauen. In dem jetzi- gem Beispielprogramm prüfen wir das System auf alle registrierten Joysticks.

Wird ein gültiger Joystick gefunden, so können wir das notwendige Gerät erstel- len. Wir aber kein Joystick gefunden, so beenden wir das Programm. Das Ergeb- nis der Prüfung übergeben wir an die Combobox1 auf Form1 unserer Anwen- dung.

Sub InitDirectInput()

Set di = dx.DirectInputCreate()

Set diDevEnum = di.GetDIEnumDevices(DIDEVTYPE_JOYSTICK, _ DIEDFL_INCLUDEPHANTOMS)

Die DirectInput.GetDIEnumDevices()-Methode füllt das Typen-Arrays diDev Enum. Die Parameter der DirectInput.GetDIEnumDevices()-Methode bestim- men, dass wir Informationen über Joysticks erhalten möchten. Die Konstante DIEDFL_INCLUDEPHANTOMS im zweiten Parameter informiert DirectInput, dass Informationen über alle vom System registrierten Joysticks gewünscht sind.

Es wird nicht unterschieden, ob der Joystick angeschlossen ist oder nicht.

If diDevEnum.GetCount = 0 Then

MsgBox "Es wurde kein Joystick gefunden."

Unload Me End If

Die Prüfung, ob überhaupt ein Joystick verfügbar ist, können wir mit DirectInput EnumDevices.GetCount()-Methode durchführen. Liefert diese Methode eine 0 zurück, so wissen wir, das kein Joystick angeschlossen ist. Ansonsten wird die Methode die Anzahl der angeschlossenen Joysticks bekannt geben.

Dim i As Integer

For i = 1 To diDevEnum.GetCount

Combo1.AddItem diDevEnum.GetItem(i).GetInstanceName JoyGuid(i) = diDevEnum.GetItem(i).GetGuidInstance Next i

(13)

Nacheinander lassen wir alle Joystickbezeichnungen in die Combobox eintragen.

Zusätzlich merken wir uns den Guid der gefundenen Joysticks, dieser wird beim Erstellen des Gerätes benötigt. Über diese Box können wir dann einen der geliste- ten Joysticks wählen und testen.

EventHandle = dx.CreateEvent(Me)

Die DirectX7.CreateEvent() liefert das Handle des Event-Objektes, welches in der Form eingebunden ist. Für den vollautomatischen Callback ist das Handle unverzichtbar.

End Sub

Schritt 2: Abfragen der Joystickfähigkeiten

Wenn das Combo1_Click()-Ereignis ausgelöst wird, ermitteln wir die Fähigkeiten des selektierten Joysticks. Ebenso ermitten wir, ob der selektierte Joystick mit dem Computer verbunden ist.

Set diDevEnum = di.GetDIEnumDevices(DIDEVTYPE_JOYSTICK, _ DIEDFL_ATTACHEDONLY)

For EunmCount = 1 To diDevEnum.GetCount If JoyGuid(Index + 1) = _

diDevEnum.GetItem(EunmCount).GetGuidInstance Then Label3 = "Joystick ist mit dem Computer verbunden"

Else

Label3 = _

"Joystick ist --> N I C H T <-- mit dem Computer verbunden"

End If

Next EunmCount

If diDevEnum.GetCount = 0 Then Label3 = "Joystick ist _ --> N I C H T <-- mit dem Computer verbunden"

Entsprechend der Prüfung ob der gewählte Joystick mit dem System verbunden ist, verändern wir den Infotext von Label3. Nur von den angeschlossenen Joy- sticks werden wir später die Daten empfangen und auf dem Bildschirm anzeigen.

Die eigentliche Prüfung der Joystickfähigkeiten übernimmt die CheckCaps()- Subroutine. Diese haben wir in drei Abschnitte unterteilt. Für die Abfrage der Achsen, Knöpfe und Coolie Steuerungen (Richtungsschalter) nutzen wir die DirectInputDevice.GetDeviceObjectsEnum()-Methode. Sie verlangt den Para- meter flags As CONST_DIDFTFLAGS. Er bestimmt welche Fähigkeit des Joy- sticks abgefragt werden soll.

Set didoEnum = diDev.GetDeviceObjectsEnum(DIDFT_AXIS)

Mit der For...Next-Schleife überprüfen wir die gefundnen Joystickfähigkeiten.

Zum Vergleich stellt uns DirectInput die CONST_DIJOYSTICKOFS-Konstan- tenliste zur Verfügung.

(14)

Beispiel: Joystick 266

For i = 1 To didoEnum.GetCount Set dido = didoEnum.GetItem(i) Select Case dido.GetOfs Case DIJOFS_X

Achsen(1) = True Case DIJOFS_Y Achsen(2) = True Case DIJOFS_Z Achsen(3) = True Case DIJOFS_RY Achsen(4) = True Case DIJOFS_RX Achsen(5) = True Case DIJOFS_RY Achsen(6) = True Case DIJOFS_SLIDER0 Achsen(7) = True Case DIJOFS_SLIDER1 Achsen(8) = True End Select

Next

In unserm Beispiel übertragen eine eine positive Prüfung der möglichen Achsen in das Array Achsen(). Die Auswertung für die Bildschirmanzeige ist gänzlich unkompliziert und muss nicht erläutert werden.

For i = 1 To 8

If Achsen(i) = True Then Check1(i – 1).Value = 1 Check1(i – 1).Enabled = True Text1(i – 1).Visible = True Else

Check1(i – 1).Value = 0 Check1(i – 1).Enabled = False Text1(i – 1).Visible = False End If

Next i

Schritt 3: Setzen der Joystickeigenschaften

Unterschiedliche Joysticks liefern unterschiedliche Wertebereiche bei der Ach- senabfrage. Da Sie als Programmierer nicht wissen können, welchen Joystick der Anwender einmal nutzen wird, legen wir den gültigen Wertebereich einfach fest.

Die Joystick werden die selbstdefinierten Grenzen beachten, sodass wir eine ein- heitliche Interpretation der empfangenen Daten erstellen können. Bevor wir uns um die Interpretation kümmern, setzen wir nun die Joystickeigenschaften. Hierzu nutzen wir die SetProperties()-Subroutine.

(15)

Public Sub SetProperties() Dim DiProp_Range As DIPROPRANGE With DiProp_Range

.lHow = DIPH_DEVICE

Da wir den Wertebereich für alle Achsen begrenzen möchten, wählen wir die Ein- stellung DIPH_DEVICE.

.lSize = Len(DiProp_Range) .lMin = 0

.lMax = 10000

Durch die Parameter lMin und lMax wird der Wertebereich der Achsen begrenzt.

Diese Berenzung wirkt sich auf alle Joysticks aus. Programmtechnisch ist solch eine Einschränkung von Nutzen, denn dadurch wird es möglich, über eine einheit- liche Routine die Daten unterschiedliche Joysticks auszuwerten. Ohne solch eine Einschränkung müsste man für verschieden Joysticks auch unterschiedliche Aus- wertungen erstellen.

End With

diDev.SetProperty "DIPROP_RANGE", DiProp_Range

Die folgenden Geräteeigenschaften definieren die Deadzone. Die Deadzone ist ein Wertebereich in dem der Joystick nicht reagieren soll. Die Mitte des Wertebe- reichs ist die Nullstellung (wenn Sie den Joystick nicht bewegen).

Dim DiProp_Dead As DIPROPLONG With DiProp_Dead

.lData = 1000

Die Deadzone wird in unserem Beispiel mit 1000 (10% der Maximalwerte) fest- gelegt. Setzen Sie diesen Wert doch mal auf 1, Sie werden beobachten, dass die Daten des Joysticks immer etwas schwanken, obwohl er sich in Nullstellung befindet.

.lSize = Len(DiProp_Dead) .lHow = DIPH_BYOFFSET .lObj = DIJOFS_X

diDev.SetProperty "DIPROP_DEADZONE", DiProp_Dead

Zuerst legen wir die Deadzone für die X Achse fest. Anschließend folgt die Defi- nition für die Y Achse.

.lObj = DIJOFS_Y

diDev.SetProperty "DIPROP_DEADZONE", DiProp_Dead End With

End Sub

(16)

Beispiel: Maus 268

Schritt 4: Direktes Empfangen der Joystickdaten per Callback-Funktion Die Joystickdaten werden über die DirectXEvent_DXCallback()-Subroutine emp- fangen. Bevor wir an die Daten gelangen, müssen wir das Gerät erstellen, das Da- tenformat festlegen, den Cooperativ Level festlegen, die Callbackbenachrichtigung einschalten und die Verbindung zu dem Gerät schaffen. Dies wird von uns im letz- ten Abschnitt der Combo1_Click()-Subroutine erledigt.

Private Sub Combo1_Click() .

. .

Set diDev = di.CreateDevice(JoyGuid(Index + 1)) diDev.SetCommonDataFormat DIFORMAT_JOYSTICK

diDev.SetCooperativeLevel Me.hWnd, DISCL_BACKGROUND Or _ DISCL_NONEXCLUSIVE

Call diDev.SetEventNotification(EventHandle) SetProperties

diDev.Acquire

Do While Running = True diDev.Poll

Die DirectInputDevice.Poll()-Methode stellt die Joystickdaten zur Verfügung.

Der Joystick wird ohne Unterbrechung Daten senden, deshalb wird auch unter- brechungsfrei die Callback-Routine aufgerufen.

DoEvents Loop

3.6 Beispiel: Maus

Der Zugriff auf die Systemmaus als Eingabegerät ist vergleichbar mit der einge- setzten Joysticktechnik. In unserem Beispiel gehen wir davon aus, dass nur eine Maus angeschlossen ist. Es entfällt somit die Auflistung der verfügbaren Einga- begeräte und wir konzentrieren uns aus die Systemmaus.

Je nachdem welche Maus der Anwender angeschlossen hat, besitzt die Maus unterschiedliche Fähigkeiten. DirectInput unterstützt folgende Objekte:

3 Achsen (X-Achse, Y-Achse und Z-Achse)

4 Knöpfe

Per Callback-Funktion fragen wir die Joystickdaten ab. Im Gegensatz zum Joy- stick sendet die Maus nicht permanent Daten, sondern nur dann, wenn Sie die Maus bewegen oder eine Taste drücken.

(17)

Schritt 1: Erzeugen des Maus-Objektes Schritt 2: Abfragen der Mausfähigkeiten Schritt 3: Setzen der Mauseigenschaften

Schritt 4: Direktes Empfangen der Mausdaten per Callback-Funktion

Neben den benötigten DirectInput-Methoden müssen wir noch einige API-Funk- tionen deklarieren. Diese sind für die Abfrage der Mausinformationen nicht not- wendig, werden aber für eine ordentliche Auswertung benötigt. In einer DirectX- Anwendung, in der Sie nicht unmittelbar mit der Windowsoberfläche arbeiten, können Sie auf diese getrost verzichten.

Implements DirectXEvent

Private Declare Function GetCursorPos Lib "user32" _ (lpPoint As POINTAPI) As Long

Private Declare Function SetCursorPos Lib "user32" _ (ByVal X As Long, ByVal Y As Long) As Long

Private Declare Function ScreenToClient Lib "user32" _ (ByVal hWnd As Long, lpPoint As POINTAPI) As Long Private Type POINTAPI

X As Long Y As Long End Type

Dim dx As New DirectX7 Dim di As DirectInput

Dim diDev As DirectInputDevice

Dim diDevEnum As DirectInputEnumDevices Dim Achsen(8) As Boolean

Bild 3.5: Bildschirmfoto Maus

(18)

Beispiel: Maus 270

Dim Knöpfe(32) As Boolean Dim EventHandle As Long Dim MausCaps As DIDEVCAPS Dim js As DIMOUSESTATE Dim Running As Boolean

Dim JoyAngeschlossen As Boolean Dim MouseX As Long

Dim MouseY As Long Dim CursorPos As POINTAPI Dim ClientWindowsLeft As Long Dim ClientWindowsTop As Long Dim ZeichenModus As Boolean Dim Speed As Long

Schritt 1: Erzeugen des Maus-Objektes Sub InitDirectInput()

Set di = dx.DirectInputCreate()

Set diDevEnum = di.GetDIEnumDevices(DIDEVTYPE_MOUSE, _ DIEDFL_ATTACHEDONLY)

If diDevEnum.GetCount = 0 Then

MsgBox "Es wurde kein Mouse gefunden."

End End If

Sollte keine Maus gefunden werden, so beenden wir das Programm. Diesmal ist es nur notwendig, das System auf angeschlossene Geräte zu prüfen. Von den an- geschlossenen Geräten interessiert uns auch nur die Maus. Für den ersten Parame- ter der DirectInput.GetDIEnumDevices()-Methode wählen wir DIDEVTYPE_

MOUSE. Dieser besagt, das wir nur nach einem Gerät vom Typ Maus suchen. Der zweite Parameter DIEDFL_ATTACHEDONLY besagt, dass wir nur angeschlos- sene Geräte suchen.

EventHandle = dx.CreateEvent(Me)

Set diDev = di.CreateDevice("guid_SysMouse")

Nachdem eine Maus gefunden wurde, können wir das Gerät erstellen. Zum Erstellen einer Systemmaus verwenden wir die Konstante guid_SysMouse.

CheckCaps

Die Prüfung der Mausfähigkeiten übernimmt die CheckCaps()-Subroutine. Diese betrachten wir im Anschluss.

diDev.SetCommonDataFormat DIFORMAT_MOUSE

diDev.SetCooperativeLevel Me.hWnd, DISCL_BACKGROUND Or ISCL_NONEXCLUSIVE

Call diDev.SetEventNotification(EventHandle) SetProperties

(19)

Nachdem wir das Gerät erstellt haben und bevor wir die Verbindung zum Gerät herstellen, können wir die Eigenschaften des Geräts festlegen. Dies übernimmt die SetProperties()-Subroutine.

diDev.Acquire Running = True

Do While Running = True DoEvents

Loop End Sub

Schritt 2: Abfragen der Mausfähigkeiten Public Sub CheckCaps()

diDev.GetCapabilities MausCaps

Wir übergeben die Mausfähigkeiten an MausCaps As DIDEVCAPS. Aus Maus- Caps benötigen wir eigentlich nur die Anzahl der Mausknöpfe. Programmtech- nisch können Sie das auch anders lösen, dies würde aber der DirectX Philosophie etwas widersprechen.

Dim didoEnum As DirectInputEnumDeviceObjects Dim dido As DirectInputDeviceObjectInstance .

. .

Prüfung der Achsen.

Set didoEnum = diDev.GetDeviceObjectsEnum(DIDFT_AXIS) For i = 1 To didoEnum.GetCount

Set dido = didoEnum.GetItem(i) Select Case dido.GetOfs Case DIMOFS_X Achsen(1) = True Case DIMOFS_Y Achsen(2) = True Case DIMOFS_Z Achsen(3) = True End Select

Next

Prüfung der Knöpfe.

Set didoEnum = diDev.GetDeviceObjectsEnum(DIDFT_BUTTON) For i = 1 To didoEnum.GetCount

Set dido = didoEnum.GetItem(i) a = dido.GetOfs

Select Case dido.GetOfs

(20)

Beispiel: DirectInput und Direct3D 272

Case DIMOFS_BUTTON0 Knöpfe(1) = True Case DIMOFS_BUTTON1 Knöpfe(2) = True Case DIMOFS_BUTTON2 Knöpfe(3) = True Case DIMOFS_BUTTON3 Knöpfe(4) = True End Select

Next . . . End Sub

Schritt 3: Setzen der Mauseigenschaften Public Sub SetProperties()

Dim DiProp_Range As DIPROPRANGE Dim diProp As DIPROPLONG

diProp.lHow = DIPH_DEVICE

diProp.lData = DIPROPAXISMODE_REL

Die Konstante DIPROPAXISMODE_REL besagt, dass die von der Maus gesen- deten Daten relative Daten sind. Dem Programmierer werden nur die Änderungen von einer Abfrage zur darauf folgenden Abfrage mitgeteilt. Sie können auch die Konstante DIPROPAXISMODE_ABS verwenden, dann erhalten Sie absolute Werte. In unserem Beispiel sind relative Daten besser auszuwerten.

diProp.lSize = Len(diProp)

Call diDev.SetProperty("DIPROP_AXISMODE", diProp) End Sub

3.7 Beispiel: DirectInput und Direct3D

Mit diesem Beispielprogramm demonstrieren wir die Integration von DirectInput in einer Direct3D-Anwendung. Nach dem Starten des Programms erhalten Sie ein Auswahlfenster. Hier können Sie zwischen einer Steuerung per Tastatur oder per Joystick wählen. Es werden Ihnen nur Joysticks, welche mit dem System verbun- den sind, angezeigt. Benutzen Sie einen analogen Joystick, so wird die Laufge- schwindigkeit entsprechend der Joystickintensität angepasst. Zusätzlich haben wir eine einfache Technik einer Kollisionserkennung eingebunden.

Die Tastatur wir diesmal per Callback abgefragt. In unserem ersten Beispiel wurde die Abfrage noch per Timerobjekt ausgeführt. Diese Lösung wäre für die- ses Beispiel nicht so geeignet. Da wir für den Joystick eine Callback-Funktion einrichten, bietet es sich an, die Tastaturabfrage in der gleichen Subroutine durch- zuführen.

(21)

Zuerst betrachten wir das Auswahlfenster für die verfügbaren Eingabegeräte.

Bevor wir ein Eingabegerät auswählen können, müssen die verfügbaren Geräte angezeigt werden. Wir gehen davon aus, dass eine Tastatur immer angeschlossen ist, sodass wir diese nicht testen und auflisten müssen. Für die Auswahl eines Joy- sticks sieht das ganz anders aus.

Private Sub Form_Load()

Set di = dx.DirectInputCreate()

Set diEnumDev = di.GetDIEnumDevices(DIDEVTYPE_JOYSTICK, _ DIEDFL_ATTACHEDONLY)

devicecount = diEnumDev.GetCount() .

. .

For i = 1 To devicecount Set diDev = _

di.CreateDevice(diEnumDev.GetItem(i).GetGuidInstance) Combo1.AddItem (diEnumDev.GetItem(i).GetProductName) Bild 3.6: Bildschirmfoto Bewegung

(22)

Beispiel: DirectInput und Direct3D 274

Alle angeschlossenen Joysticks werden in die Comb1-Combobox eingetragen.

Diese Prozedur ist Ihnen bereits bekannt und kann im Beispielprogramm »Auflis- ten der verfügbaren Geräte und Objekte« nachgelesen werden.

Next i

Combo1.Text = Combo1.List(0) Listen 1

Die Subroutine Listen() zeigt die Joystickfähigkeiten an. Auch diese ist Ihnen bekannt und wird jetzt nicht näher erklärt.

End Sub

Nachdem Sie das Eingabegerät gewählt haben, klicken Sie auf die Schaltfläche Weiter.

Private Sub Command1_Click()

If Label5 = "N/A" Or Label6 = "N/A" Then MsgBox "Sie haben _ keine Eingabegerät gewählt!": Exit Sub

Sollten Sie kein Eingabegerät gewählt haben, verlassen wir die Subroutine direkt.

Bild 3.7: Bildschirmfoto Bewegung (Login)

(23)

InputName = Label5 InputGuid = Label6

Die Variablen InputName und InputGuid nutzen wir, um später das Eingabegerät zu erzeugen. InputName dient hauptsächlich dazu, um die beiden Eingabegeräte (Tastatur oder Joystick) zu unterscheiden.

Unload Me Load Form1 End Sub

Weiter geht es mit der Subroutine Form_Load() von Form1.

Private Sub Form_Load() InitDDraw

InitD3D InitInput Licht RenderState MakeVertex .

. . End Sub

Die Subroutine InitInput() richtet das Eingabegerät ein. Bevor wir auf weitere Elemente der Form_Load()-Subroutine eingehen, schauen wir uns die InitIn- put()-Subroutine genauer an.

Public Sub InitInput() Select Case Form2.InputName Case "Tastatur"

Set di = g_dx.DirectInputCreate() EventHandle = g_dx.CreateEvent(Me)

Set diDev = di.CreateDevice("GUID_SysKeyboard")

Beim Einrichten der Tastatur sind wir auf eine individuelle Guid nicht angewie- sen. Wir können die feste Kennung GUID_SysKeyboard verwenden.

diDev.SetCommonDataFormat DIFORMAT_KEYBOARD

diDev.SetCooperativeLevel Me.hWnd, DISCL_BACKGROUND Or _ DISCL_NONEXCLUSIVE

Call diDev.SetEventNotification(EventHandle) diDev.Acquire

Case Else

Set di = g_dx.DirectInputCreate() EventHandle = g_dx.CreateEvent(Me)

Set diDev = di.CreateDevice(Form2.InputGuid)

(24)

Beispiel: DirectInput und Direct3D 276

Für das Erzeugen des Joysticks benötigen wir eine individuelle Guid. Diese wurde bei der Joystickauswahl ermittelt und in der Variablen InputGuid gespei- chert.

diDev.SetCommonDataFormat DIFORMAT_JOYSTICK

diDev.SetCooperativeLevel Me.hWnd, DISCL_BACKGROUND Or _ DISCL_NONEXCLUSIVE

Call diDev.SetEventNotification(EventHandle) SetProperties

diDev.Acquire End Select End Sub

Um die Eingabedaten zu empfangen, haben wir uns bei beiden Eingabemöglich- keiten für eine Callback-Funktion entschieden.

Private Sub DirectXEvent_DXCallback(ByVal eventid As Long) On Local Error Resume Next

If InputFrei = False Then Exit Sub InputFrei = False

If diDev Is Nothing Then Exit Sub If Form2.InputName <> "Tastatur" Then diDev.GetDeviceStateJoystick js SpeedY = (5000 – js.y) / 5000 SpeedX = ((5000 – js.x) / 500) * -1

Als wir den Joystick erzeugt haben, wurden auch die Joystickeigenschaften neu definiert. Die Subroutine SetProperties() beschränkt den Wertebereich der Joy- stickachsen auf 0 bis 10000. Die Mittelstellung liegt also bei 5000. Wir werden also von allen Joysticks Daten in einem gemeinsamen Wertebereich erhalten, somit sind wir in der Lage, die Daten programmtechnisch auszuwerten. Die Daten übergeben wir an die globalen Variablen SpeedY und SpeedX.

Else

diDev.GetDeviceStateKeyboard ks

If ks.Key(200) And OldButton <> 200 Then SpeedY = 0.3

OldButton = 200 End If

If ks.Key(208) And OldButton <> 208 Then SpeedY = -0.3

OldButton = 208 End If

If ks.Key(203) And OldButton <> 203 Then SpeedX = -4

OldButton = 203 End If

If ks.Key(205) And OldButton <> 205 Then

(25)

SpeedX = 4 OldButton = 205 End If

If ks.Key(200) = 0 And ks.Key(208) = 0 Then SpeedY = 0

OldButton = 0 End If

If ks.Key(203) = 0 And ks.Key(205) = 0 Then SpeedX = 0

OldButton = 0 End If

If ks.Key(200) <> 0 And ks.Key(208) <> 0 Then SpeedY = 0

OldButton = 0 End If

If ks.Key(203) <> 0 And ks.Key(205) <> 0 Then SpeedX = 0

OldButton = 0 End If

Für die Datenauswertung der Tastatur mussten wir die Tastatureigenschaften nicht neu definieren. Schließlich gibt es für eine Taste nur zwei Zustände (ge- drückt oder nicht gedrückt). Anders als beim Joystick werden die empfangenen Daten auch nicht weiter interpretiert. Drücken Sie z.B. die Vorwärtstaste, so wird die Geschwindigkeit direkt auf einen festen Wert gesetzt. In unserem Beispiel auf 0.3. Analoge Zwischenwerte existieren nicht.

End Sub

Nachdem wir die Eingabegeräte erzeugt haben und in der Lage sind, die Eingabe- daten zu empfangen, werden die Informationen in der Form_Load()-Subroutine von Form1 weiter ausgewertet.

Private Sub Form_Load() .

. . Do

If g_dx.TickCount > TimerZeit + ZeitInterval Then TimerZeit = g_dx.TickCount

tempVector.x = BetrachterPos.x tempVector.z = BetrachterPos.z

Wir haben eine kleine Kollisionserkennung in das Programm eingebunden. Diese soll folgende Aufgabe lösen: »Erkennen einer Kollision mit einem Baum zwei Einheiten vor unserer aktuellen Laufrichtung«. Es ist wichtig, dass Sie eine mög- liche Kollision vor Ihrer aktuellen Position prüfen. Wir haben uns für zwei Ein- heiten vor uns entschieden. Wenn wir den Abstand zu unserer Position zu klein

(26)

Beispiel: DirectInput und Direct3D 278

wählen, treten unschöne Effekte (der Betrachter steht halb in dem Baum, der Betrachter kann durch den Baum sehen ...) auf.

If SpeedY > 0 Then

If speed > 2 Then xx = speed Else xx = 2 tempVector2.x = BetrachterPos.x + (xx * _ Sin(BetrachterWinkel / 57.296))

tempVector2.z = BetrachterPos.z + (xx * _ Cos(BetrachterWinkel / 57.296))

Else

If speed < 2 Then xx = speed * -1 Else xx = 2 tempVector2.x = BetrachterPos.x – (xx * _ Sin(BetrachterWinkel / 57.296))

tempVector2.z = BetrachterPos.z – (xx * _ Cos(BetrachterWinkel / 57.296))

End If

Beim Erzeugen der Bäume in der MakeVertex()-Subroutine haben wir das Typen- Arrays Kollision mit den Baumkoordinaten gefüllt. Diese Daten können wir nun für die Kollisionserkennung nutzen. Dazu fragen wir eine rechteckigen Bereich um den Baum herum ab. Befinden wir uns in diesem Bereich, dann wird eine Kol- lision erkannt.

For i = 1 To 60

If tempVector2.x > Kollision(i).PosX – 0.5 And _ tempVector2.x < Kollision(i).PosX + 0.5 And _ tempVector2.z > Kollision(i).PosZ – 0.5 And _ tempVector2.z < Kollision(i).PosZ + 0.5 Then BetrachterPos.x = tempVector.x

BetrachterPos.z = tempVector.z kolli = 1

Exit For

Wenn eine Kollision erkannt wurde, wird die Betrachterposition nicht verändert.

Der Betrachter verharrt an einer Stelle, ohne sich in die angestrebte Richtung bewegen zu können.

Else

kolli = 0 End If Next i

If kolli = 0 Then

BetrachterPos.x = BetrachterPos.x + _ (SpeedY * Sin(BetrachterWinkel / 57.296)) BetrachterPos.z = BetrachterPos.z + _ (SpeedY * Cos(BetrachterWinkel / 57.296))

(27)

Wurde keine Kollision erkannt, so darf der Betrachter die neue Position einneh- men.

End If

BetrachterWinkel = BetrachterWinkel + SpeedX BetrachterSicht.x = BetrachterPos.x + _ 100 * Sin(BetrachterWinkel / 57.296) BetrachterSicht.z = BetrachterPos.z + _ 100 * Cos(BetrachterWinkel / 57.296) BetrachterPos.y = 1.5

BetrachterSicht.y = 1.5

Call g_dx.ViewMatrix(matView, BetrachterPos,_

BetrachterSicht, MakeVector(0, 1, 0), 0)

g_d3dDevice.SetTransform D3DTRANSFORMSTATE_VIEW, matView

Durch die Transformation der ViewMatrix werden die Veränderungen von Betrachterposition und Betrachterblickwinkel für den Anwender sichtbar.

. . . End Sub

3.8 Bewegung im 3D-Raum

Position, Ausrichtung und Blickrichtung des Betrachters oder der Spielfigur wird im Allgemeinen über die Viewmatrix berechnet. Diese Parameter werden über verschiedene Vektoren festgelegt. Als Erstes haben wir die absolute Position im dreidimensionalen Raum. Diese Werte splitten sich in die drei Vektorkoordinaten x, y und z auf. Als Nächstes benötigen wir xyz Koordinaten für den Punkt auf den wir blicken, weiterhin können wir die Kopfneigung und Drehung festlegen. In unserem Beispiel beschränken wir uns zunächst auf die ersten beiden Parameter.

Das Problem:

Über den ersten 3D-Vektor sind wir generell in der Lage uns durch einen beliebi- gen Raum zu bewegen. Allerdings würden wir immer auf einen bestimmten Punkt (0,0,0) im Raum schauen. Würden wir zum Beispiel ein Objekt umkrei- sen, wäre diese Technik angebracht. Die Position des Betrachters würde sich stets verändern und der Blick fiele immer auf das umkreiste Objekt.

Diese Vorhergehensweise macht bei einsetzbaren Anwendungen wenig Sinn.

Vielmehr versucht man die Realität nachzuahmen, getreu dem Motto » Ich gehe, wohin ich sehe.« Viele Programme benutzen hierzu eine bewährte Steuerungs- technik. Betätigt man die Links-Rechts-Cursortasten, so dreht sich der Betrachter um die eigene Achse. Drückt man nun die Vor-Zurück-Cursortasten, bewegt man sich in die Richtung, in die man gerade schaut.

(28)

Bewegung im 3D-Raum 280

Um diese Eigenart zu simulieren, benötigen wir einen Blickrichtungsvektor.

Stellen wir uns vor, wir könnten genau 5 Meter weit sehen und wir würden uns einmal um unsere eigene Achse drehen. So würde das Ende unseres Blickfeldes einen Kreis mit einem Radius von 5 Metern um uns ziehen.

Das hieße also, die Blickrichtung liegt auf einem Kreisbogen um uns herum und unsere jetzige Standposition ist der Mittelpunkt dieses Kreises.

Bild 3.8: Umkreisen eines Objekts im 3D-Raum

Bild 3.9: Blickrichtung

(29)

Anhand der Grafik sehen wir, dass der Blickpunkt über einfache geometrische Kreisberechnungen ermittelt werden kann. Berücksichtigt werden muss nur noch, dass wir weiter sehen können, als wir mit einem Schritt gehen können. Hierzu berechnen wir einfach einen neuen Standort auf einem kleineren Kreisbogen, den wir dann der alten Position hinzuaddieren können.

So viel zur Theorie. Was nun folgt, ist die Praxis.

Unsere aktuellen Standortvariablen benennen wir (AktX,AktZ). Als Weiteres benötigen wir die aktuelle Blickrichtung in Grad. Nennen wir diese AktBR.

Um nun eine Drehung auszuführen, müssen wir AktBR in einem Bereich von 0-359 Grad verändern.

Für die Tastaturabfrage eignet sich der API-Aufruf GetAsyncKeyState, den wir in einer DoEvents-Endlosschleife auf einen vorhandenen Tastendruck abfragen.

Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer

Dim AktX as Single Dim AktZ as Single Dim AktBR as Single Private Sub Schleife() Do

Drehung links um die Y-Achse

If GetAsyncKeyState(vbKeyLeft) <> 0 then AktBR = AktBR -1

If AktBR <0 then AktBR=359 End If

Bild 3.10: Berechnung des neuen Standorts auf einen neuen Blickpunkt hin

(30)

Bewegung im 3D-Raum 282

Drehung rechts um die Y-Achse

If GetAsyncKeyState(vbKeyRight) <> 0 then AktBR = AktBR+1

If AktBR >359 then AktBR=0 end if

Berechnung des Positionsabgleichs Vorwärtsbewegung.

If GetAsyncKeyState(vbKeyUp) <> 0 then px = 0.5 * Cos( AktBR / 180 / Pi ) pz = 0.5 * Sin( AktBR / 180 / Pi ) AktX = AktX + px

AktZ = AktZ + pz End If

Berechnung des neuen Blickpunktes.

BlickX = 100 * Cos (AktBR / 180 / Pi ) BlickY = 100 * Sin (AktBR / 180 / Pi ) Call g_dx.ViewMatrix(matView, _

MakeVector(AktX,0,AktZ), MakeVector(BlickX, _ 0, BlickY), MakeVector(0, 1, 0), 0)

Loop End Sub

Private Function MakeVector( a As Double, b As Double, _ c As Double ) as D3DVECTOR

Dim vecOut as D3DVECTOR vecOut.x = a

vecOut.y = b vecOut.z = c MakeVector = vecOut End Function

Bild 3.11: Berechnung der neuen Position im Koordinatensystem

Referenzen

ÄHNLICHE DOKUMENTE

Damals hatte eine meiner Vorgängerinnen zusammen mit den Staats- und Regierungschefs aller Länder der Erde einen Aktionsplan „für die Menschen, den Pla- neten und den

Interpreter, interpreter Schablonenmethode Beobachter, observer Kommando, transaction Memento, token Strategie, policy Vermittler, mediator Zustand, state. Zuständigkeitskette, chain

Interpreter, interpreter Schablonenmethode Beobachter, observer Kommando, transaction Memento, token Strategie, policy Vermittler, mediator Zustand, state. Zuständigkeitskette, chain

Interpreter, interpreter Schablonenmethode Beobachter, observer Kommando, transaction Memento, token Strategie, policy Vermittler, mediator Zustand, state. Zuständigkeitskette, chain

Interpreter, interpreter Schablonenmethode Beobachter, observer Kommando, transaction Memento, token Strategie, policy Vermittler, mediator Zustand, state. Zuständigkeitskette, chain

Neben Privathaushalten entsorgt der ASP auch eine Viel- zahl kleinerer und mittlerer Gewerbebetriebe. Sowohl für Restabfall, als auch für Wertstoffe bieten wir Ihnen sehr

Der neue Studiengang des Instituts Sekundarstufe I der PHBern ermöglicht Personen, die bereits über einen Bachelorabschluss einer Universität oder Fachhochschule in

a) Die Sparkasse/Landesbank darf die digitale Kreditkarte mit individuali- sierten Authentifizierungsverfahren sperren (z. durch Löschung), wenn sie berechtigt ist, den