Multitouch mit Windows 7

Werbung
LABORPROJEKT
Multitouch mit Windows 7
SS2010
Jan Sören Ramm (Tinf6303)
Tobias Möllmann (Tinf6302)
26.6.2010
Inhaltsverzeichnis
Abbildungsverzeichnis ...................................................................................................................... 4
1
Einleitung .................................................................................................................................... 5
2
Was ist Multitouch? ................................................................................................................... 6
3
4
5
2.1
Voraussetzungen .............................................................................................................. 6
2.2
Vorteile ................................................................................................................................ 6
Windows 7 - Multitouch API..................................................................................................... 7
3.1
Windows Touch-Gesten ................................................................................................... 7
3.2
Grundsätzliches Konzept ................................................................................................. 8
3.3
Manipulations-Prozessoren und Inertia ......................................................................... 9
3.4
Was macht die API und was muss selbst implementiert werden? ..........................10
Entwicklungsumgebung .........................................................................................................12
4.1
Programmiersprache ......................................................................................................12
4.2
Erstellen eines Multitouch Projektes ............................................................................12
Multitouch Beispiel ..................................................................................................................16
5.1
5.1.1
Verschieben ...............................................................................................................16
5.1.2
Rotieren ......................................................................................................................16
5.1.3
Zoomen .......................................................................................................................17
5.1.4
Zwei-Finger-Klick.......................................................................................................17
5.1.5
Berühren und mit dem zweiten Finger klicken......................................................17
5.2
6
Multitouch-Rechteck .......................................................................................................16
Implementierung ..............................................................................................................18
5.2.1
DrawingObject.h ........................................................................................................18
5.2.2
DrawingObject.cpp ....................................................................................................19
TicTacToe.................................................................................................................................27
6.1
Bedienung ........................................................................................................................27
6.1.1
Ablaufbedingungen ...................................................................................................27
6.1.2
Programmstart ...........................................................................................................27
6.1.3
Programmzweck ........................................................................................................27
6.1.4
Programmausführung ...............................................................................................28
6.1.5
Spiel beginnen ...........................................................................................................28
6.1.6
Spielstein setzen .......................................................................................................28
6.1.7
Wechsel des Spielfeldes ..........................................................................................28
6.1.8
Veränderung der Objekteigenschaften ..................................................................29
6.1.9
Spielende ....................................................................................................................29
6.1.10 Weitere Optionen ......................................................................................................29
6.2
7
Programmierung ..............................................................................................................30
6.2.1
Anforderungen ...........................................................................................................30
6.2.2
Implementierung ........................................................................................................31
6.2.3
Klassen .......................................................................................................................39
6.2.4
Use-Case Diagramm ................................................................................................42
Probleme bei der Implementierung ......................................................................................43
7.1
CPU – Auslastung ...........................................................................................................43
7.2
Netzwerkverzögerung.....................................................................................................43
7.3
Blockieren des Anwendungsfensters bei aktiven Popupboxen ...............................44
8
Fazit ...........................................................................................................................................45
9
Literaturverzeichnis .................................................................................................................46
Abbildungsverzeichnis
Abb. 1: Windows API Touch-Gesten (1)........................................................................................ 7
Abb. 2: Konzept der Touch-Nachrichten (2) ................................................................................. 8
Abb. 3: Das Konzept der Manipulations-Prozessoren (2) .......................................................... 9
Abb. 4: Intertia Konzept (2) ............................................................................................................10
Abb. 5: Neues Projekt.....................................................................................................................13
Abb. 6: Anwendungstyp-Fenster ..................................................................................................13
Abb. 7: Benutzeroberflächenfeatures ..........................................................................................14
Abb. 8: Erweiterte Features Dialog ..............................................................................................14
Abb. 9: Geste – Verschieben (3) ..................................................................................................16
Abb. 10: Geste – Rotation (3)........................................................................................................16
Abb. 11: Geste – Zoom (3) ............................................................................................................17
Abb. 12: Geste - Zwei Finger Klick (3) .........................................................................................17
Abb. 13: Geste - Berühren und mit dem zweiten Finger klicken (3) .......................................17
Abb. 14: Rotes Rechteck beim Programmstart ..........................................................................23
Abb. 15: Positionsermittlung Ausgangszustand .........................................................................32
Abb. 16: Positionsermittlung - Spielfeld in Ursprung verschoben ...........................................32
Abb. 17: Positionsermittlung - Spielfeld rotiert............................................................................33
Abb. 18: Positionsermittlung - Spielfeld skaliert .........................................................................33
Abb. 19: Klassendiagramm............................................................................................................39
Abb. 20: Use-Case Diagramm ......................................................................................................42
1 Einleitung
Am 22. Oktober 2009 hat Microsoft das neue Betriebssystem „Windows 7― vorgestellt und
in diesem Zuge die neuen Multitouch-Funktionalitäten. Im Rechnernetzelabor wurde
schnell darauf reagiert und Multitouch-Hardware in Form eines Monitores angeschafft, um
die Möglichkeiten von Multitouch zu Testen und darauf evtl. im Rahmen eines Laborprojektes eine kleine Anwendung zu entwickeln und damit einen tieferen Einblick in die Möglichkeiten zu bekommen.
Aufgrund dieser Ereignisse entstand die Idee für dieses Laborprojekt. Es sollte das Spiel
„TicTacToe― mit Multitouch-Funktionalität implementiert werden. Der Fokus dieses Projektes lag darauf, die Multitouch-Funktionalitäten von Windows 7 kennen zu lernen und eine
Anleitung zu verfassen, die beschreibt, wie die Windows 7 Multitouch-Funktionalitäten
verwendet werden können. Dies sollte der Grundstein für weitere Multitouch-Projekte werden. Des Weiteren sollten kleine Probleme, die bei der Implementierung auftreten dokumentiert werden, um in folgenden Projekten diese Probleme im Vorfelde vermeiden zu
können.
Durch die Aktualität des Themas hat sich bereits während des Laborprojektes einiges verändert, wie z.B. die Empfehlung der zu verwendenden Programmiersprache.
Dieses Beispiel verdeutlicht, dass sich diese Technologie noch im Wandel befindet, jedoch
zum aktuellen Zeitpunkt bereits viele Funktionen bietet die einen gespannt in die Zukunft
Kapitel: Einleitung
blicken lässt.
5
2 Was ist Multitouch?
Der Begriff „Multitouch― wird meistens im Zusammenhang mit der Erkennung von mehreren „Touch―-Punkten gleichzeitig genannt. Durch die Erkennung von mehreren gleichzeitigen Berührungspunkten als Eingabe, ergeben sich viele neue Gestiken, die eine intuitive
Bedienung ermöglichen können. Zu beachten gilt es, dass bei Tablet-PCs von dem Hersteller „Lenovo― bereits vor einigen Jahren der Begriff Multitouch gefallen ist, jedoch war
damit die abwechselnde Eingabe durch Finger und Stift gemeint.
2.1 Voraussetzungen
Um Multitouch-Funktionalitäten nutzen zu können, muss Multitouch-Hardware zur Verfügung stehen (Touchscreen mit mindestens zwei Erkennungspunkten).
Außerdem muss zum aktuellen Zeitpunkt ein Windows 7 installiert sein, jedoch befindet
sich eine Multitouch API für Linux bereits in der Entwicklung.
2.2 Vorteile
Die Multitouch-Technologie bietet ganz neue Bedienmöglichkeiten, die als Mausersatz
verwendet werden können. Dadurch können Fragen wie: „Warum wird das Mausrad, wenn
man sich mit dem Mauszeiger über einem Bild befindet, zum Zoomen verwendet und andernfalls zum Scrollen?― vermieden werden. Das Zoomen wird realisiert durch das A useinanderziehen eines Bildes mit Hilfe von zwei Fingern. Gescrollt wird durch Verschieben
des Hintergrundes mit einem Finger. Zum jetzigen Zeitpunkt existiert noch kein Standard,
der bestimmte Gesten mit Aktionen versieht. Die Windows 7 API suggeriert zwar bestimmte Aktionen bei bestimmten Gesten über die Funktionsnamen der API, aber an diese Vor-
Kapitel: Was ist Multitouch?
schläge muss der Programmierer sich nicht halten.
6
3 Windows 7 - Multitouch API
Windows 7 stellt eine API zur Verfügung mit dessen Hilfe „relativ einfach― MultitouchGesten behandelt werden können. Diese API und die entsprechenden Funktionalitäten
sowie die zugrunde liegenden Konzepte, werden im Folgenden vorgestellt.
3.1 Windows Touch-Gesten
Die Windows 7 Multitouch API erkennt diverse Gesten, welche in der folgenden Tabelle
Abb. 1: Windows API Touch-Gesten (1)
Kapitel: Windows 7 - Multitouch API
genauer beschrieben werden.
7
3.2 Grundsätzliches Konzept
Abb. 2: Konzept der Touch-Nachrichten (2)
Die linke Spalte der Grafik stellt die Hardware / Windows Kernel-Ebene dar. Ein Treiber
der Multitouch-Hardware kommuniziert mit dem Windows Kernel und übermittelt lediglich
die Eingabedaten. Windows generiert daraus standardisierte Nachrichten vom Typ
„WM_TOUCH― bzw. „WM_GESTURE―, die an die hWnd (eindeutige Fensteridentifizierungsnummer) der Anwendung übermittelt werden. Die Anwendung kann diese Daten
auswerten bzw. verwerfen. Dabei gilt es zu beachten, dass Touch-Events „gierig― sind und
Geste dieses Fenster die entsprechenden Nachrichten erhält, auch wenn die Geste außerhalb des Fensters fortgesetzt wird. Windows stellt mit dem .Net-Framework 4 Standardfunktionalitäten zur Verfügung wie „Panning―, „Zoom― und „Press and Hold―. Diese
Funktionen werden auf Aktionen mit Standardeingabegeräten abgebildet.
Pan  Mausrad
Press and Hold  Rechtsklick mit der Maus
Zoom  Strg + Mausrad
Kapitel: Windows 7 - Multitouch API
mit dem Beginn einer Touch-Geste die hWnd bestimmt wird und bis zum Ende der Touch-
8
Um bei selbst entwickelter Multitouch-Funktionalität die Standardfunktionalitäten verwenden zu können, sollten „WM_GESTURE― Nachrichten mit Hilfe der Funktion DefWindowProc weitergeleitet werden.
3.3 Manipulations-Prozessoren und Inertia
Abb. 3: Das Konzept der Manipulations-Prozessoren (2)
Diese Grafik beschreibt die weitere Interpretation, der durch Windows bereitgestellten
punktes einer Berührung angereichert. Mit Hilfe dieser Koordinaten kann die Anwendung
bestimmen, welches Objekt, falls mehrere vorhanden sind, das aktive ist. Jedes Objekt
beinhaltet einen Manipulationsprozessor, der die Nachrichten einer Berührungsfolge erhält. Dort werden die Nachrichten ausgewertet und in sogenannte ManipulationEvents
umgewandelt, die daraufhin ausgelöst werden. Auf die entsprechenden Events wird meistens ein Eventlistener hinzugefügt, um die entsprechenden Reaktionen des Userinterfaces
darzustellen (z.B. neue Form des Objektes berechnen und zeichnen).
Kapitel: Windows 7 - Multitouch API
Nachrichten. Jede Nachricht wird mit den X- und Y-Koordinaten des ersten Berührungs-
9
Abb. 4: Intertia Konzept (2)
Windows stellt eine einfache Physik-Engine zur Verfügung, die Inertia 1 heißt. Diese Physik-Engine sorgt dafür, dass Objekte nach dem Loslassen nicht abrupt stoppen, sondern je
nach Beschleunigung langsam weiter rutschen bis zum Stillstand. Das Konzept des Inertia-Prozessors wird in der obigen Grafik verdeutlicht. Jedes manipulierbare Objekt enthält
ein Inertia-Prozessor-Interface und sendet die Manipulationsdaten an den InertiaProzessor. Dieser Inertia-Prozessor ist für die Auswertung dieser Daten zuständig und löst
die zugehörigen ManipulationEvents aus. Die ausgelösten Events müssen von der A n-
3.4 Was macht die API und was muss selbst implementiert werden?
Die API erkennt Finger, ebenso wie die Gesten, die ausgeführt werden. Außerdem stehen
diverse Manipulationsdaten zur Verfügung, wie z.B. ein Manipulationsdelta etc. Über diese
Daten kann die komplette Manipulation vorgenommen werden. Es muss dagegen selbst
bestimmt werden, welches Objekt gerade das aktive ist sowie, wie das Objekt sich daraufhin verhalten soll (z.B. die Rotation eines Objektes muss selbst berechnet werden, der
1
Auch Trägheitsprozessor genannt
Kapitel: Windows 7 - Multitouch API
wendung angenommen und verarbeitet werden.
10
Winkel ist im Manipulationsdelta enthalten). Bei weiteren Gesten, die nicht im Abschnitt
3.1 beschrieben sind, müssen die Touch-Rohdaten durch die Anwendung ausgewertet
Kapitel: Windows 7 - Multitouch API
werden um die selbst definierten Gesten zu erkennen.
11
4 Entwicklungsumgebung
Als Entwicklungsumgebung diente während des Laborprojektes Visual Studio 2008 mit
.Net 3.5 SP1, da dort die API von Windows 7 Multitouch zur Verfügung gestellt werden
kann. Zum aktuellen Zeitpunkt wurde Visual Studio 2010 veröffentlicht, worin viele Konfigurationsaufgaben für die Entwicklung von Multitouch Anwendungen vom Visual Studio
übernommen werden. Im Weiteren wird die Entwicklung unter Verwendung von Visual
Studio 2010 beschrieben, um diese Dokumentation sinnvoll für zukünftige Projekte nutzbar
zu machen.
4.1 Programmiersprache
Als Programmiersprache im Laborprojekt diente Visual C#, wobei dies im Ermessen des
Programmierers liegt, da das .Net Framework dieselben Multitouch-Funktionalitäten auch
für Visual Basic und Visual C++ zur Verfügung stellt. Visual C# ist eine Java ähnliche Programmiersprache und kann mit geringer Einarbeitungszeit von allen Studenten, die die
OOP Vorlesung gehört haben, benutzt werden. Visual C++ ist ähnlich wie ANSI C, jedoch
steht Objektorientierung zur Verfügung. Visual C++ ist bereits nach der ANSI C Vorlesung
verwendbar, jedoch sollten grundsätzliche Kenntnisse der Objektorientierung vorhanden
sein. Bei dem folgenden kleinen Tutorial wird Visual C++ verwendet, da diese Sprache
auch in den meisten offiziellen Bespielen von Microsoft verwendet wird. In kleineren Beispielen ist die Komplexität eines Visual-C++-Programms deutlich geringer als die eines
entsprechenden Visual C#-Programms. Des Weiteren wird von Microsoft aus Performanz-
4.2 Erstellen eines Multitouch Projektes
Im Rahmen dieses Laborprojektes ist ein kleiner Screencast entstanden, welcher die folgenden Schritte sowie die Umsetzung von Kapitel 5 „Multitouch Beispiel― beinhaltet.2
2
Auf der CD unter /doc/Screencasts/tutorial/index.html zu finden
Kapitel: Entwicklungsumgebung
Gründen empfohlen Visual C++ zu verwenden.
12
Als erstes wird in Visual Studio ein neues Projekt erzeugt. Dabei sollte als Template Visual
C++  MFC Anwendung ausgewählt werden (.Net Framework 4) und dieser Dialog mit
„Ok― bestätigt werden.
Abb. 5: Neues Projekt
Im Anwendungstyp-Fenster sollten die Einstellungen aus dem Screenshot übernommen
Abb. 6: Anwendungstyp-Fenster
Kapitel: Entwicklungsumgebung
werden:
13
Im Benutzeroberflächenfeatures-Dialog sollten die folgenden Einstellungen vorgenommen
werden:
Abb. 7: Benutzeroberflächenfeatures
Abb. 8: Erweiterte Features Dialog
Kapitel: Entwicklungsumgebung
Im „Erweiterte Features― Dialog sollten die folgenden Einstellungen vorgenommen werden:
14
Anschließend „Weiter― drücken und die Standardeinstellungen übernehmen, bis das neue
Projekt erzeugt wurde.
Anschließend wird die „.cpp― Datei mit dem Projektnamen geöffnet und in der
InitInstance() folgender Programmausschnitt zur Überprüfung der Multitouch Hardware am
Ende eingefügt:
BYTE digitizerStatus = (BYTE) GetSystemMetrics(SM_DIGITIZER);
if ((digitizerStatus & (0x80 + 0x40)) == 0) //Stack Ready + MultiTouch
{
AfxMessageBox(L"Es steht keine Touchhardware zur Verfuegung!");
return FALSE;
}
BYTE nInputs = (BYTE) GetSystemMetrics(SM_MAXIMUMTOUCHES);
CString str;
str.Format(L"Touchhardware gefunden mit %d Erkennungpunkten.", nInputs);
AfxMessageBox(str);
return TRUE;
Mit diesem Stück Quelltext wird erreicht, dass das Programm lediglich gestartet wird,
wenn Multitouchhardware zur Verfügung steht. Außerdem wird ausgegeben, wie viele Erkennungspunkte von der Hardware unterstützt werden.
Kapitel: Entwicklungsumgebung
Dies ist ein Grundgerüst, auf dem das folgende Beispielprogramm aufbaut.
15
5 Multitouch Beispiel
Im Folgenden wird anhand eines kleinen Beispiels gezeigt, wie mit einer MFC-Anwendung
rudimentäre Multitouch-Funktionalitäten implementiert werden können. Dieses Beispiel
baut auf einem Microsoft Tutorial auf, welches im aus der Quelle (3) stammt.
5.1 Multitouch-Rechteck
In diesem Beispiel soll ein Rechteck auf einer Zeichenfläche gezeichnet werden, das auf
folgende Ereignisse reagiert:
5.1.1 Verschieben
Durch Berühren und Verschieben von zwei Fingern im Anwendungsfenster soll das
Rechteck bewegt werden können, horizontal wie auch vertikal. Die folgende Abbildung
demonstriert die Verwendung dieser Geste.
Abb. 9: Geste – Verschieben (3)
5.1.2 Rotieren
Durch Berührung des Rechtecks mit zwei Fingern und anschließendem Rotieren der Fin-
Abb. 10: Geste – Rotation (3)
Kapitel: Multitouch Beispiel
ger soll das Rechteck um seinen Mittelpunkt gedreht werden.
16
5.1.3 Zoomen
Durch Berühren und Zusammenführen bzw. Auseinanderführen von zwei Fingern soll das
Rechteck verkleinert bzw. vergrößert werden.
Abb. 11: Geste – Zoom (3)
5.1.4 Zwei-Finger-Klick
Ein Klick auf das Rechteck mit zwei Fi ngern gleichzeitig soll das abwechselnde Ein- und
Ausblenden der Hauptdiagonalen zur Folge haben.
Abb. 12: Geste - Zwei Finger Klick (3)
Das Berühren mit einem Fingen und anklicken mit einem zweiten Finger soll einen Wechsel der Hintergrundfarbe des Rechtecks zur Folge haben.
Abb. 13: Geste - Berühren und mit dem zweiten Finger klicken (3)
Kapitel: Multitouch Beispiel
5.1.5 Berühren und mit dem zweiten Finger klicken
17
5.2 Implementierung
Zu Beginn muss ein neues Projekt erzeugt werden, wie im Abschnitt 4.2 beschrieben.
5.2.1 DrawingObject.h
Zuerst wird ein Rechteck mit allen Manipulationsfunktionen benötigt, die durch die entsprechenden Gesten ausgelöst werden. Dazu wird eine neue Klasse mit dem Namen
DrawingObject und dem folgenden Code im Headerfile erzeugt.
#pragma once
#include "stdafx.h"
#include <windows.h>
#include <math.h>
#define MAX_COLORS 5
class DrawingObject
{
public:
DrawingObject(void);
// Objekt in den Ursprungszustand versetzen
void ResetObject(const int cxClient,const int cyClient);
// Rechteck Zeichnen
void Paint(HDC hdc);
// Rechteck bewegen
void Move(LONG ldx,LONG ldy);
// Diagonalen Aktivieren / Deaktivieren
void TogleDrawDiagonals(void){_bDrawDiagonals = !_bDrawDiagonals;}
// Rechteck Zoomen
void Zoom(const double dZoomFactor,const LONG iZx,const LONG iZy);
// Rechteck drehen
void Rotate(const double dAngle,const LONG iOx,const LONG iOy);
// nächste Farbe als Hintergrundfarbe setzen
void ShiftColor(void);
private:
// Array mit Farben
static const COLORREF s_colors[];
// Mittelpunkt des Rechtecks
LONG
_iCx;
LONG
_iCy;
// Grundgröße des Rechtecks
int
_iWidth;
int
_iHeight;
// Skalierungsfaktor
double _dScalingFactor;
Kapitel: Multitouch Beispiel
public:
~DrawingObject(void);
18
// Rotationswinkel des Rechtecks relative zur X-Achse
double _dRotationAngle;
// Boolean ob die Hauptdiagonalen gezeichnet werden sollen.
bool
_bDrawDiagonals;
// Farbe des Rechtecks
int
_iColorIndex;
};
In diesem Headerfile wird die Klasse DrawingObject weiter spezifiziert. Es werden alle Methoden sowie die entsprechenden Attribute und Konstruktoren definiert.
5.2.2 DrawingObject.cpp
Anschließend wird die Klasse DrawingObject in der „.cpp― Datei ausprogrammiert und
sieht folgendermaßen aus:
#include "stdafx.h"
#include "DrawingObject.h"
// Alle Farben die das Rechteck annehmen kann.
const COLORREF DrawingObject::s_colors[] =
{
RGB(210,0,0),
// RED
RGB(13,13,13),
// black
RGB(255,139,23), // yellow
RGB(146,208,80), // green
RGB(149,179,215) // blue
};
// Konstruktor
DrawingObject::DrawingObject(void)
{
}
// Nächste Hintergrundfarbe auswählen
void DrawingObject::ShiftColor(void)
{
// Farbindes ein erhöhen
_iColorIndex++;
// wieder die erste verwenden falls Index größer als size(s_colors[])
if(MAX_COLORS == _iColorIndex)
{
_iColorIndex = 0;
}
}
Kapitel: Multitouch Beispiel
// Destruktor
DrawingObject::~DrawingObject(void)
{
}
19
//Setzt die Initialwerte des Rechtecks in Abhängigkeit von der Fenstergröße
//sollte bei der Änderung der Fenstergröße aufgerufen werden.
// in:
//
cxClient - Fensterbreite
//
cyClient - Fensterhöhe
void DrawingObject::ResetObject(const int cxClient,const int cyClient)
{
// Mittelpunkt des Rechtecks ist die Fenstermitte
_iCx = cxClient/2;
_iCy = cyClient/2;
// Rechteckgröße = halbe Fenstergröße
_iWidth = cxClient/2;
_iHeight = cyClient/2;
// Scalierung auf 1 setzen => kein Zoom
_dScalingFactor = 1.0;
// Standard Rotation auf 0° setzen => keine Rotation
_dRotationAngle = 0.0;
_bDrawDiagonals = false; // Diagonalen nicht zeichnen
_iColorIndex = 0; // Standardfarbe ist Rot
}
// Zeichnet das Rechteck auf eine Zeichenfläche
// in:
//
hdc - Zeichenfläche
void DrawingObject::Paint(HDC hdc)
{
//Minimale Rechteckgröße auf 5% der originalgröße festlegen
double localScale = 1.0;
localScale = max(_dScalingFactor, 0.05);
// Stift erzeugen zu Zeichnen
HPEN hPen = CreatePen(PS_SOLID,6,RGB(0,0,0));
// Stift als Zeichenstift festlegen
HGDIOBJ hPenOld = SelectObject(hdc,hPen);
// Rechteckpunkte bestimmen
POINT ptRect[5];
ptRect[1].x = (LONG)(localScale * _iWidth/2);
ptRect[1].y = ptRect[0].y;
ptRect[2].x = ptRect[1].x;
ptRect[2].y = (LONG)(localScale * _iHeight/2);
ptRect[3].x = ptRect[0].x;
ptRect[3].y = ptRect[2].y;
ptRect[4].x = ptRect[0].x;
ptRect[4].y = ptRect[0].y;
// Rotation des Rechtecks
Kapitel: Multitouch Beispiel
ptRect[0].x = -(LONG)(localScale * _iWidth/2);
ptRect[0].y = -(LONG)(localScale * _iHeight/2);
20
double dCos = cos(_dRotationAngle);
double dSin = sin(_dRotationAngle);
for(int i=0; i<5; i++)
{
LONG lDX = ptRect[i].x;
LONG lDY = ptRect[i].y;
ptRect[i].x = (LONG)(lDX*dCos + lDY*dSin);
ptRect[i].y = (LONG)(lDY*dCos - lDX*dSin);
}
// Rechteck verschieben
for(int i=0; i<5; i++)
{
ptRect[i].x += _iCx;
ptRect[i].y += _iCy;
}
// Hintergrundfläche Malen
HRGN hrgn = CreatePolygonRgn(ptRect,5,WINDING);
if(hrgn)
{
HBRUSH hbr = CreateSolidBrush(s_colors[_iColorIndex]);
if(hbr)
{
FillRgn(hdc,hrgn,hbr);
DeleteObject(hbr);
}
DeleteObject(hrgn);
}
// Umrandung Malen
Polyline(hdc,ptRect,5);
// Diagonalen Malen
if(_bDrawDiagonals)
{
MoveToEx(hdc,ptRect[0].x,ptRect[0].y,NULL);
LineTo(hdc,ptRect[2].x,ptRect[2].y);
MoveToEx(hdc,ptRect[1].x,ptRect[1].y,NULL);
LineTo(hdc,ptRect[3].x,ptRect[3].y);
// Zeichenfläche aufräumen
SelectObject(hdc,hPenOld);
DeleteObject(hPen);
}
// Mittelpunkt des Rechtecks neu setzen
// in:
//
ldx – vergrößerung / verkleinerung der X-Koordinate
//
ldy – vergrößerung / verkleinerung der Y-Koordinate
void DrawingObject::Move(LONG ldx,LONG ldy)
{
_iCx += ldx;
_iCy += ldy;
}
Kapitel: Multitouch Beispiel
}
21
// Zoomfaktor setzen
// in:
//
dZoomFactor - Zoomfaktor
//
iZx
- X-Zoommittelpunkt (nicht benötigt)
//
iZy
- Y-Zoommittelpunkt (nicht benötigt)
void DrawingObject::Zoom(const double dZoomFactor,const LONG iZx,const LONG iZy)
{
_dScalingFactor *= dZoomFactor;
}
// Rotationsetzen
// in:
//
dAngle - Rotationsgrad
//
iOx
- X-Rotationsmittelpunkt (nicht benötigt)
//
iOy
- Y-Rotationsmittelpunkt (nicht benötigt)
void DrawingObject::Rotate(const double dAngle,const LONG iOx,const LONG iOy)
{
_dRotationAngle += dAngle;
}
Anschließend wird in den obersten Zeilen der „ChildView.h― die „DrawingObject.h― und die
Mathe-Bibliothek mit den folgenden Zeilen eingebunden.
#include "DrawingObject.h"
#define _USE_MATH_DEFINES
#include <math.h>
In der ChildView.h wird anschließend eine globale Variable vom Typ DrawingObject definiert. Dies geschieht durch das Einfügen von folgender Zeile in dem Bereich der „protected― Felder.
DrawingObject g_drawingObject;
Außerdem werden zum Zeichnen und Positionieren drei weitere Variablen benötigt, die in
dem Bereich der „protected― Felder einzufügen sind:
Damit das Objekt gezeichnet wird, muss folgende Zeile in die Funktion CChildView::OnPaint() hinzugefügt werden:
g_drawingObject.Paint(dc);
Damit das Objekt neu skaliert wird, wenn die Größe des Fensters verändert wird, muss bei
der Klasse CChildView die „WM_SIZE― Message behandelt werden. Dies kann in der
Kapitel: Multitouch Beispiel
double m_dblZoomRatioStart;
double m_dblZoomRatioTotal;
CPoint m_ptCenter;
22
Klassenansicht unter Nachrichten ausgewählt werden. Der Inhalt der automatisch erzeugten Methode ist folgender:
g_drawingObject.ResetObject(cx,cy);
Jetzt kann das erste Mal kompiliert werden. Es sollte ein Fenster erscheinen mit ei nem
Abb. 14: Rotes Rechteck beim Programmstart
Jetzt kann sich um die wirklichen Multitouch-Nachrichten gekümmert werden. Dafür müssen in der „ChildView.h― einige Definitionen hinzugefügt werden. Diese Definitionen
gehören in den „protected override―-Bereich.
Kapitel: Multitouch Beispiel
mittig gezeichnetem roten Rechteck, wie im folgenden Screenshot nochmal verdeutlicht.
23
virtual
virtual
virtual
virtual
virtual
BOOL
BOOL
BOOL
BOOL
BOOL
OnGestureZoom(CPoint ptCenter, long lDelta);
OnGesturePan(CPoint ptFrom, CPoint ptTo);
OnGestureRotate(CPoint ptCenter, double dblAngle);
OnGesturePressAndTap(CPoint ptFirstFinger, long lDelta);
OnGestureTwoFingerTap(CPoint ptCenter);
Diese definierten Methoden müssen in der „CChildView.cpp― ausprogrammiert werden.
Diese Methoden werden automatisch beim Empfangen von den entsprechenden Touch
Nachrichten aufgerufen. Im ersten Schritt wird die „OnGesturePan―-Methode implementiert. Diese berechnet die Differenz der Bewegung und bewegt das Rechteck an die entsprechende Position.
BOOL CChildView::OnGesturePan(CPoint ptFrom, CPoint ptTo)
{
int dx = ptTo.x - ptFrom.x;
int dy = ptTo.y - ptFrom.y;
if (dx != 0 || dy != 0)
{
g_drawingObject.Move(dx, dy);
RedrawWindow();
}
return TRUE;
}
Als zweites wird die Zoom-Geste implementiert, hierbei gilt es zu beachten, dass die erste
Nachricht verworfen wird, da dies auch ein „schlechter― Pan sein könnte:
g_drawingObject.Zoom(zoomFactor, ptCenter.x, ptCenter.y);
m_dblZoomRatioStart = m_dblZoomRatioTotal;
RedrawWindow();
}
return TRUE;
}
Kapitel: Multitouch Beispiel
BOOL CChildView::OnGestureZoom(CPoint ptCenter, long lDelta)
{
if ((m_pCurrentGestureInfo->dwFlags & GF_BEGIN) == GF_BEGIN)
{
m_dblZoomRatioStart = m_dblZoomRatioTotal = lDelta;
}
else if (lDelta != 0)
{
m_dblZoomRatioTotal += lDelta;
double zoomFactor = (double)m_dblZoomRatioTotal / m_dblZoomRatioStart;
24
Weiter geht es mit der Rotationsgeste und auch hier wird die erste Nachricht aus obigem
Grund verworfen:
BOOL CChildView::OnGestureRotate(CPoint ptCenter, double dblAngle)
{
if ((m_pCurrentGestureInfo->dwFlags & GF_BEGIN) == GF_BEGIN)
{
// Make the first center, the rotating one
m_ptCenter = ptCenter;
}
else if (dblAngle != 0.)
{
g_drawingObject.Rotate(dblAngle * M_PI / 100.0, m_ptCenter.x, m_ptCenter.y);
RedrawWindow();
}
return TRUE;
}
PressAndTap sieht ähnlich aus:
BOOL CChildView::OnGesturePressAndTap(CPoint ptFirstFinger, long lDelta)
{
if ((m_pCurrentGestureInfo->dwFlags & GF_BEGIN) != 0)
{
g_drawingObject.ShiftColor();
RedrawWindow();
}
return TRUE;
}
Und zum Abschluss TwoFingerTap:
BOOL CChildView::OnGestureTwoFingerTap(CPoint ptCenter)
{
g_drawingObject.TogleDrawDiagonals();
RedrawWindow();
return TRUE;
Anschließen kann das Projekt erneut kompiliert und ausgeführt werden.
Folgendes Verhalten ist zu erwarten:
Mit zwei Fingern kann das Rechteck verschoben werden, jedoch funktioniert dies im gesamten Programmfenster, da keine Überprüfung stattfindet ob die Berührungspunkte i nnerhalb des Rechtecks liegen.
Kapitel: Multitouch Beispiel
}
25
Es sollten alle Touch-Gesten, abgesehen von der Rotations-Geste funktionieren. Die Rotations-Geste wird standardmäßig nicht an das Anwendungsfenster weitergeleitet. Im folgenden Schritt wird eingerichtet, dass alle Touch-Messages vom Fenster empfangen werden.
Hierfür muss die „ChildView.h― abermals editiert werden und eine weitere „protected―Variable eingeführt werden:
CGestureConfig m_gestureConfig;
Anschließend
muss
in
der Klassenansicht
unter
„Nachrichten―
(Icon)
auf die
„WM_CREATE―-Nachricht gewartet werden. Die „WM_CREATE― Methode sollte folgendermaßen aussehen:
GetGestureConfig(&m_gestureConfig);
m_gestureConfig.EnableRotate();
SetGestureConfig(&m_gestureConfig);
Nach diesem Schritt ist das Demoprogramm fertig gestellt und hat hoffentlich einen klei-
Kapitel: Multitouch Beispiel
nen Einblick in die Touch-Message gegeben.
26
6 TicTacToe
Dieses Kapitel beschreibt die Bedienung und die Programmierung der TicTacToeAnwendung. Es wird unter anderem darauf eingegangen, was bei der Implementierung zu
beachten ist und welche Klassen verwendet wurden. Auf der beiliegenden CD ist ein kurzer Screencast, der beschreibt, wie dieses Projekt kompiliert werden kann und wie das
Ergebnis dieser Implementierung aussieht.3
6.1 Bedienung
Dieser Abschnitt behandelt die Anforderungen und beschreibt den Spielablauf vom Start
des Programms bis hin zum Spielende.
6.1.1 Ablaufbedingungen
Um das Spiel TicTacToe starten zu können, muss es unter Windows 7 ausgeführt werden.
Es muss eine multitouchfähige Hardware zur Verfügung stehen. Das Spiel ist für mehrere
Spieler entworfen worden, daher sollte der Rechner, auf dem es ausgeführt wird, am
Netzwerk angeschlossen sein. Es ist auch möglich, das Spiel an einem PC gegeneinander
zu spielen, allerdings leidet der Bedienungskomfort darunter.
6.1.2 Programmstart
Der Inhalt des Ordners „/bin―, zu finden auf der beiliegenden CD, ist in einen beliebigen
Ordner zu kopieren, von dem aus die ausführbare Datei gestartet werden kann.
6.1.3 Programmzweck
TicTacToe ist ein intuitives Spiel für zwei Spieler. Gespielt wird auf einem Feld der Größe
3 mal 3. Jeder Spieler muss abwechselnd auf ein noch freies Feld einen Spielstein legen.
Der Spieler, der zuerst drei Steine in einer Reihe, einer Spalte oder einer der Hauptdiagonalen hat, gewinnt das Spiel. Es ist auch möglich, dass keiner der Spieler die Gewinnbe-
Dieses Spiel ist als Multitouch-Anwendung umgesetzt, da dies der intuitiven Bedienung
zugutekommt.
3
Zu finden unter /doc/Screencasts/TicTacToe/
Kapitel: TicTacToe
dingung erfüllt, womit das Spiel im Remis endet.
27
6.1.4 Programmausführung
Nach dem Programmstart sind zunächst nur das Hintergrundbild und eine Menüleiste zu
sehen. Bevor ein Spiel gestartet werden kann, muss eine Verbindung zu einem anderen
Spieler über das Netzwerk aufgebaut werden.
6.1.5 Spiel beginnen
Um ein neues Spiel zu beginnen, muss der Hauptmenüpunkt „Server erstellen“ ausgewählt werden. Danach kann ein anderer Spieler diesem Spiel beitreten. Dazu muss die
gleiche Anwendung entweder auf demselben oder auf einem anderen, per Netzwerk verbundenem, Rechner laufen. Der Spieler tritt dem Spiel bei, indem der Spieler auf „Teilnehmen“ klickt. Zunächst öffnet sich ein neues Fenster, da die IP-Adresse des ersten
Spielers für die Verbi ndung notwendig ist. Ist diese korrekt eingegeben und die Verbindung konnte aufgebaut werden, startet das Spiel. Beim momentan aktiven Spieler 1 erscheint das Spielfeld, der zu setzende Spielstein, sowie zwei Knöpfe zum Setzen des
Spielsteins und zum Zurücksetzen der Position des Spielsteins und des Spielfeldes. Der
passive Spieler kann die Aktivität des ersten Spielers mitverfolgen, indem auch bei ihm
das Spielfeld zu sehen ist, allerdings in grau, um zu symbolisieren, dass er momentan keinen Zugriff darauf hat.
6.1.6 Spielstein setzen
Der aktive Spieler setzt seinen Stein, indem er diesen mit Hilfe eines Fingers auf die gewünschte Position des Spielfeldes zieht. Durch Drücken des entsprechenden Knopfes wird
der Zug bestätigt. Dies ist durch den abgespielten Sound („Klick―) erkennbar. Befindet sich
der Stein nicht auf dem Spielfeld oder auf einem belegten Feld, ertönt ebenfalls ein spezielles Geräusch, welches dies verdeutlicht. Der Spieler ist weiterhin an der Reihe.
Konnte der Spieler seinen Stein erfolgreich se tzen, ist sein Gegenspieler am Zug. Bei ihm
erscheint der entsprechende Stein. Er kann den Stein allerdings noch nicht setzen, da sich
6.1.7 Wechsel des Spielfeldes
Um das Spielfeld zwischen den beiden Spielern zu tauschen, muss es über den rechten
Rand des Fensters hinaus bewegt werden. Anhand der Einfärbung des Spielfeldes kann
Kapitel: TicTacToe
das Spielfeld noch immer bei dem ersten Spieler befindet.
28
jeder Spieler erkennen, ob sich das Feld momentan bei ihm oder dem Spieler gegenüber
befindet.
6.1.8 Veränderung der Objekteigenschaften
Sowohl das Spielfeld als auch der Spielstein kann durch jeden Spieler manipuliert werden.
Es ist möglich, die Objekte zu drehen, zu bewegen oder die Größe zu ändern.
Ausgewählt wird das Objekt, welches bei einem Touch getroffen wird. Ist kein Objekt an
der direkten Position, wird auch keines selektiert. Wenn sich sowohl Spielstein als auch
das Feld an der Stelle befinden, hat der Stein die höhere Priorität. Bereits gelegte Spie lsteine können nicht mehr ausgewählt werden.
Das Bewegen eines Objektes ist mit einem Finger möglich. Wird der Finger während der
Bewegung von der Touchoberfläche genommen, hat das Objekt noch eine gewisse Geschwindigkeit, die sich bis zum Stillstand reduziert. Falls sich das Objekt außerhalb des
Fensters bewegt, kann es durch Drücken auf den Knopf „Position zurücksetzen“ an seine
Ursprungsposition zurückgesetzt werden. Der Knopf ist nur bei dem Spieler sichtbar, der
Zugriff auf das Spielfeld hat.
Zum Zoomen und Drehen werden zwei Finger benötigt. Die Größe wird durch das Entfernen bzw. Annähern von zwei Fingern skaliert. Für eine Drehung müssen die Finger um
einen Punkt herum gedreht werden.
6.1.9 Spielende
Sobald einer der Spieler gewonnen hat, wird das Spiel beendet. Es können keine weiteren
Steine mehr gesetzt werden. Abhängig davon, ob ein Spieler gewinnt, verliert oder das
Spiel unentschieden ausgegangen ist, erscheint eine entsprechende Meldung und ein entsprechender Sound wird abgespielt.
6.1.10 Weitere Optionen
Da verschiedene Benutzer unterschiedliche Wünsche bezüglich des Designs haben, ist es
möglich sowohl das Hintergrundbild als auch die Spielfeldfarbe zu ändern. Dies kann im
Hauptmenü unter den entsprechenden Punkten realisiert werden.
Kapitel: TicTacToe
Nach Beendigung können beide Spieler im Hauptmenü ein neues Spiel starten.
29
Um dauerhaft visuelle oder auditive Einstellungen zu verändern, müssen die notwendigen
Dateien in den Unterordnern images bzw. sound ersetzt werden. Dabei muss die neue
Bild- oder Audiodatei den kompletten Namen mitsamt Endung übernehmen.
Um den Netzwerkverkehr nachvollziehen zu können, ist in der Menüleiste eine Zeitmessung eines Paketes zum Gegenspieler und zurück möglich. Die gemessene Zeit wird in
Millisekunden angegeben.
6.2 Programmierung
In diesem Abschnitt werden die Anforderungen und die Umsetzung der Programmierung
genauer
erläutert.
Die
Quelltexte
dieses
Projektes
sind
auf
der
CD
unter
„src/Demo/Multitouch/MultitouchWinForms/mtManipulation― wiederzufinden.
6.2.1 Anforderungen
Um die Möglichkeiten der Programmierung von Multitouch-Anwendungen zu veranschaulichen, wurde das Spiel TicTacToe ausgewählt, das eine sehr einfache Logik hat und intuitiv zu bedienen ist. Für das Spiel sind zwei Spieler notwendig. Das Spiel sollte vor allem
übers Netzwerk genutzt werden, da eine abwechselnde Bedienung auf einem Bildschirm
sehr unkomfortabel ist. Somit muss hier über eine Netzwerkkommunikation nachgedacht
werden.
Ein wesentlicher Bestandteil soll die Manipulation des Spielfeldes und des Spielsteins
sein. Hierzu gehört das Drehen, Zoomen und Bewegen von Objekten. Durch welche
Touch-Ereignisse diese Manipulationen durchgeführt werden sollen, muss noch diskutiert
werden.
Die Spielsteine können auf dem Spielfeld platziert werden, indem sie per „Drag and Drop―
auf ein freies Feld gezogen werden. Damit der Spieler sich noch Gedanken über seinen
setzt werden. Stattdessen ist es sinnvoll, dass der Zug manuell bestätigt wird. Damit jeder
Spieler weiß, wann er an der Reihe ist, sollte nur der Stein des momentan ziehenden
Spielers sichtbar sein. Falls ein Spielzug nicht möglich ist, weil sich der Stein auf einem
belegten Feld oder neben dem Spielfeld befindet, sollte der Spieler ein entsprechendes
Signal bekommen, denkbar wäre ein spezifischer Sound für jedes Ereignis.
Kapitel: TicTacToe
Zug machen kann, sollte der Stein nicht sofort beim Beenden der Touch-Bewegung ge-
30
Damit weitere Multitouch-Aktivitäten gefördert werden, sollten weitere bestimmte Interaktivitäten sinnvoll eingesetzt werden. So kann über eine Spielvariante nachgedacht werden,
bei der nur ein Spieler Zugriff auf das Spielfeld hat. Wenn das Spielfeld außerhalb des
Zeichenbereiches bewegt wird, ist ein Wechsel zum anderen Spieler möglich. Damit der
Spieler ohne Spielfeld allerdings auch die Bewegungen mitverfolgen kann, sollte bei ihm
das Spielfeld auch angezeigt werden, allerdings in einer unterscheidbaren Darstellung.
Ein durchaus wichtiger mathematischer Anteil ist die Erkennung, auf welchem Feld des
Spielfeldes sich ein Spielstein befindet. Da sowohl Spielstein als auch Spielfeld gedreht,
translatiert und deren Größe verändert wird, ist hier eine aufwändige mathematische Methode notwendig.
6.2.2 Implementierung
Das Spielfeld besteht bei TicTacToe aus 3x3 Feldern. Nach jedem Spielzug muss überprüft werden, ob der neu gelegte Stein zusammen mit den bereits gelegten Steinen drei
Steine gleicher Farbe in einer Reihe, Spalte oder einer der Hauptdiagonalen ergibt. Wenn
dies der Fall ist, hat der Spieler, der den Stein gelegt hat, gewonnen. Gibt es noch keinen
Gewinner, wird überprüft, ob das Spielfeld bereits voll ist (alle neun Felder belegt), womit
es zu einem Unentschieden käme. Trifft keiner der Fälle zu, ist der Gegenspieler am Zug.
Die Algorithmen zur Überprüfung sollen hier jedoch nicht genauer erläutert werden, da sie
recht simpel sind.
6.2.2.1 Positionsermittlung des Spielsteins
Die Berechnung, ob sich ein Spielstein beim Legen im Spielfeld befindet und wenn ja, in
welchem Feld genau, soll anhand eines Beispiels erklärt werden:
Im unteren Bild ist das Spiel zu einem beliebigen Zeitpunkt dargestellt.
Das nicht manipulierte Spielfeld ist gestrichelt gezeichnet. Das Zentrum liegt im Koordina-
und bewegt. Der rote Punkt ist die Position, an der momentan der zu setzende Spielstein
liegt.
Kapitel: TicTacToe
tenursprung. Das rote Quadrat ist das aktuelle Spielfeld. Es wurde beliebig rotiert, skaliert
31
Abb. 15: Positionsermittlung Ausgangszustand
Um zu berechnen, ob sich der Mittelpunkt des Spielsteins im Spielfeld befindet, wird wie
folgt vorgegangen: Zunächst wird das Koordinatensystem so verschobe n, dass sich der
Ursprung im Zentrum des aktuellen Spielfeldes befindet:
Abb. 16: Positionsermittlung - Spielfeld in Ursprung verschoben
sind alle Seiten des Quadrates, welches das Spielfeld darstellt, parallel zu einer der Koordinatenachsen:
Kapitel: TicTacToe
Als nächstes wird das Koordinatensystem um den Winkel des Spielfeldes gedreht. Nun
32
Abb. 17: Positionsermittlung - Spielfeld rotiert
In der letzten Manipulation wird das Koordinatensystem um den Skalierungsfaktor des
Spielfeldes geändert. Damit sind das aktuelle und das ursprüngliche Spielfeld deckungsgleich:
Abb. 18: Positionsermittlung - Spielfeld skaliert
Nach diesen Manipulationen des Koordinatensystems muss nur noch überprüft werden,
ob sich der Mittelpunkt des Spielsteins innerhalb des ursprünglichen Spielfeldes befindet.
Dazu müssen folgende Bedingungen erfüllt sein:

Spielsteinmitte.X <= Betrag (Rechteckbreite / 2)

Spielsteinmitte.Y <= Betrag (Rechteckhöhe / 2)
Wenn beide Bedingungen erfüllt sind, befindet sich der Spielstein auf dem Spielfeld. Um
zu berechnen, auf welchem der neun Felder der Spielstein liegt, kann diese Methode ent-
6.2.2.2 Multitoucherkennung und –verarbeitung
6.2.2.2.1 Manipulations- und Trägheitsprozessor
In der Implementierung von TicTacToe ist die Multito uch-Erkennung wie empfohlen durch
Eventhandling realisiert. Bei der Initialisierung ist dabei einiges zu beachten. Zunächst
Kapitel: TicTacToe
sprechend fortgeführt werden.
33
muss ein Prozessor für Bewegungs- und Trägheitsverarbeitung erstellt werden. Bei der
Initialisierung wird bereits mitgeteilt, welche Manipulationsereignisse unterstützt we rden.
Das kann skalieren, rotieren oder eine Translation in eine bestimmte Richtung sein. In di esem Fall werden all diese Ereignisse gleichzeitig benötigt:
ManipulationInertiaProcessor _processor = new
ManipulationInertiaProcessor(ProcessorManipulations.ALL, Factory.CreateTimer());
6.2.2.2.2 Touchereignisse
Es gibt verschiedene Arten von Touchereignissen, z.B. TouchDown-, TouchUp- oder
TouchMove-Ereignisse. Beim TouchDown-Ereignis muss die genaue Position ermittelt
werden. Außerdem ist das Objekt zu ermitteln, auf welches die Touch-Manipulation angewendet werden soll.
_touchHandler.TouchDown += (s, e) => { _processor.ProcessDown((uint)e.Id, e.Location); };
_touchHandler.TouchDown += SelectActiveObject;
In der Eventbehandlung wird allerdings nur ein Objekt ausge wählt, wenn kein anderes
Touchereignis aktiv ist, sich also kein weiterer Finger auf der Touch-Oberfläche befindet.
Es wird das Objekt selektiert, welches an der Position des Ereignisses liegt. Dabei hat der
Spielstein Vorrang vor dem Spielfeld.
Beim TouchUp-Ereignis wird die Position weiterverarbeitet, ebenso wird das Flag, ob sich
ein Finger auf der Oberfläche befindet, gelöscht:
_touchHandler.TouchUp += (s, e) => { _processor.ProcessUp((uint)e.Id, e.Location); };
_touchHandler.TouchUp += removeFirstFinger;
Beim Bewegen des Fingers auf der Touch-Oberfläche wird ein TouchMove-Ereignis ausgelöst, bei dem das selektierte Objekt bewegt werden muss:
_touchHandler.TouchMove += (s, e) => { _processor.ProcessMove((uint)e.Id, e.Location); };
wird ein Event ausgelöst. Darin werden die relativen Änderungen zu den vorherigen Positionen angegeben. Unter anderem werden in der Behandlung des Events die Trägheitsparameter neu berechnet:
_processor.ManipulationDelta += ProcessManipulationDelta;
private void ProcessManipulationDelta(object sender, ManipulationDeltaEventArgs e)
Kapitel: TicTacToe
Sobald sich die Position, Rotation oder Translation des selektierten Objektes verändert,
34
In dieser Implementierung soll das selektierte Objekt nur mit zwei Fingern rotiert werden
können. Bei einer Translation des Objektes mit einem Finger findet also keine Rotation
statt:
_processor.PivotRadius = 0;
6.2.2.2.3 Trägheit
Für die Berechnung der Trägheit von Objekten, sodass diese sich nach dem Beenden der
Touch-Ereignisse weiterbewegen können, ist eine Trägheitsklasse (InertiaParam) implementiert worden. Darin ist die momentane „Geschwindigkeit― von Translation, Rotation und
Skalierung gespeichert. Diese Werte werden beim Update regelmäßig neu gesetzt. Dafür
muss die verstrichene Zeit exakt gemessen werden kann. Dafür liefert das .Net Framework die Klasse „System.Diagnostics.Stopwatch“, die auch verwendet wird.
Bei Starten von Manipulationsbewegungen werden die Trägheitsparameter alle zurückgesetzt, da das ausgewählte Objekt nun per Hand bewegt wird. Außerdem wird die Zeitmessung gestartet.
_processor.ManipulationStarted += (s, e) => { _inertiaParam.Reset (); };
Beim Beenden einer Manipulation wird die aktuelle Zeitmessung gestoppt:
_processor.ManipulationCompleted += (s, e) => { _inertiaParam.Stop(); };
Direkt bevor die Trägheit einsetzt, wird ein weiteres Event ausgelöst, in dem alle Trägheitsparameter initialisiert werden:
_processor.BeforeInertia += OnBeforeInertia;
In dieser Ereignisbehandlung werden die Bewegungen des Objekts bereits alle im Voraus
void OnBeforeInertia(object sender, BeforeInertiaEventArgs e)
{
//Zeitliche Auflösung des Trägheitsprozesses in ms
_processor.InertiaProcessor.InertiaTimerInterval = 15;
//maximale Ausführungen des Trägheitsprozesses(Timeraufrufe)
_processor.InertiaProcessor.MaxInertiaSteps = 500;
//Initialisierung der Bewegung
_processor.InertiaProcessor.InitialVelocity = _inertiaParam._initialVelocity;
Kapitel: TicTacToe
bestimmt:
35
//Distanz des Objektes, die dieses zurücklegen soll
_processor.InertiaProcessor.DesiredDisplacement =
_inertiaParam._initialVelocity.Magnitude * 250;
//Initialisierung der Rotation
_processor.InertiaProcessor.InitialAngularVelocity =
_inertiaParam._initialAngularVelocity * 20F / (float)Math.PI;
//erwünschter Winkel, um den sich das Objekt drehen soll
_processor.InertiaProcessor.DesiredRotation =
Math.Abs(_inertiaParam._initialAngularVelocity *
_processor.InertiaProcessor.InertiaTimerInterval * 540F / (float)Math.PI);
//Initialisierung der Vergößerung
_processor.InertiaProcessor.InitialExpansionVelocity =
_inertiaParam._initialExpansionVelocity * 15;
//erwünschte Veränderung der Größe
_processor.InertiaProcessor.DesiredExpansion =
Math.Abs(_inertiaParam._initialExpansionVelocity * 4F);
}
Das Fenster, auf dem gespielt wird, ist mit einem Rahmen umrandet, der verhindert, dass
Objekte mittels Trägheitsbewegungen komplett den sichtbaren Bereich verlassen können.
Dafür gibt es folgende Befehle:
_processor.InertiaProcessor.Boundary = new RectangleF(x, y, width, height);
_processor.InertiaProcessor.ElasticMargin = new RectangleF(x, y, width, height);
Dabei ist „Boundary― die Grenze, die nicht verlassen werden kann. Daran prallt das bewegte Objekt ab. Ein Objekt kann sich außerhalb des „ElasticMargin― bewegen, beschleunigt allerdings wieder auf das Innere des Rechtecks zu. Diese Grenzen gelten nur, wenn
ein Objekt noch eine Trägheitsbewegung hat und nicht direkt durch Touch-Ereignisse gesteuert wird. Durch Bewegen eines Objekts per Touch-Ereignis kann es also die Grenzen
verlassen.
6.2.2.3 Sound
Beim Abspielen von Sounds gibt es viele Implementierungen. Das Problem ist jedoch,
dass je nach Implementierung nur bestimmte Sound-Formate unterstützt werden. Da
TicTacToe auf Windows 7 laufen muss, können Windows-Bibliotheken verwendet werden,
Für den Import von DLL-Dateien eignet sich die .Net-Klasse „DllImportAttribute― im Namensraum „System.Runtime.InteropServices―. In „winmm.dll― gibt es eine Funktion
„mciSendString―, die einem MCI-Gerätetreiber ein Kommando sendet, um eine Multimediadatei abzuspielen, zu stoppen oder ähnliches. Mit dem Kommando „open― wird beispielsweise eine Mediadatei geöffnet und mit „play― wird sie abgespielt.
Kapitel: TicTacToe
die zahlreiche Formate unterstützen. Dies macht das Programm sehr benutzerfreundlich.
36
Die
genaue
Dokumentation
der
Funktion
ist
im
Internet
nachzulesen
unter:
http://www.vbarchiv.net/api/api_mcisendstring.html.
6.2.2.4 Netzwerkkommunikation
Für die Netzwerkkommunikation gibt es grundsätzlich zwei Möglichkeiten: Eine verbi ndungslose, ungesicherte UDP-Verbindung oder eine verbindungsorientierte, gesicherte
TCP-Verbindung. Der Vorteil der UDP-Kommunikation liegt darin, dass eine Kommunikation zwischen beliebig vielen Partnern möglich ist. Mit einer TCP-Verbindung ist lediglich
eine bidirektionale Kommunikation zwischen zwei Sockets möglich. Der Programmieraufwand bei der Implementierung der TCP-Kommunikation ist deutlich geringer, aufgrund der
Eigenschaft, dass Datenverluste automatisch erkannt und behoben werden. Da das Spiel
TicTacToe nur zu zweit gespielt werden kann, wird das TCP-Protokoll verwendet.
Um im Netzwerk spielen zu können, muss zunächst einer der Spieler den Server darstellen, der auf eine Verbindung wartet. Da dieses Warten auf eingehende Daten aktiv ist,
empfiehlt es sich, einen eigenen Thread einzusetzen, damit während des Wartevorgangs
die Interaktion mit dem Programm nicht blockiert wird. Sobald eine Verbindung hergestellt
wurde, sollte auf beiden Seiten weiterhin das Abhorchen des Netzwerkverkehrs in einen
eigenen Thread ausgelagert werden, da:
1. ansonsten die Interaktion mit dem Programm verhindert wird
2. Daten zufällig, zu nicht definierten Zeitpunkten, über das Netzwerk geschickt werden.
Die Auswertung der Netzwerkdaten sollte jedoch im Hauptprogramm erfolgen. Dies kann
mit Hilfe von Semaphoren realisiert werden, die regelmäßig auf Veränderungen überprüft
werden. Eleganter ist es jedoch, Ereignisse zu erzeugen, die in Unterbrechungsroutinen
des Hauptthreads abgearbeitet werden. Daher wurde diese Möglichkeit implementiert.
interpretieren. Für diese Daten wurde folgendes Befehlsformat erarbeitet: Als Trennzeichen zwischen einzelnen Daten dient der Doppelpunkt ':'. Jedes Datum beginnt mit einem
spezifischen Wort für die Erkennung, um welchen Befehl es sich handelt. Die genauen
Kommandos sehen wie folgt aus:
Kapitel: TicTacToe
Es muss ein bestimmtes Befehlsformat festgelegt werden, um erhaltene Daten richtig zu
37
Befehl
Funktion
Erläuterung
place:X-Koord
Setzen eines Steins
X-Koord und Y-Koord sind jeweils eine
Y-Koord
einstellige Koordinatenangabe (Feld 1-3)
des Spielfeldes
Close
Schließen der Verbindung
newGame
Starten eines neuen Spiels
switch:Y-Pos:
Wechsel des Spielfeldes
Y-Pos als prozentuale Höhenangabe
scalingFactor:
zwischen den beiden Spie-
des Spielfeldes, gemessen an der Fens-
rotationAngle
lern
terhöhe
scalingFactor als Skalierungsfaktor
rotationAngle als Winkel
change:X-Pos:Y-Pos:
Veränderung der Objekt-
X-Pos und Y-Pos als prozentuale Anga-
scalingFactor:
manipulationen von Spiel-
ben im Vergleich zur Fenstergröße
rotationAngle
feld und Spielsteinen
scalingFactor als Skalierungsfaktor
test
Starten einer Zeitmessung
2test
Antwort der Zeitmessung
Kapitel: TicTacToe
rotationAngle als Winkel
38
6.2.3 Klassen
Abb. 19: Klassendiagramm
6.2.3.1 Constants
Die Constants-Klasse enthält diverse Konstanten, wie z.B. die Spielericons und den Netzwerkport.
6.2.3.2 Settings
Diese Klasse ist für Settings des Programms zuständig. Es können bestimmte Events, wie
Veränderungen an Einstellungen des Programms verarbeitet werden. Diese Klasse wird
6.2.3.3 MainForm
Die MainForm-Klasse beinhaltet die Programmsteuerung und die Erzeugung des Anwendungsfensters. Die MainForm-Klasse kann von externen Threads nicht verändert werden.
Um dies dennoch zu ermöglichen, müssen Semaphore oder Ereignisse verwendet werden. Mit deren Hilfe wird die MainForm informiert, dass neue Informationen vorliegen. Dies
Kapitel: TicTacToe
jedoch nicht verwendet, wurde aber automatisch mit Erstellung des Projektes erzeugt.
39
wird z.B. bei der Netzwerkkommunikation verwendet um der MainForm mitzuteilen, dass
neue Daten empfangen wurden, damit diese abgerufen und verarbeitet werden.
6.2.3.4 InputBox
Diese Klasse wird verwendet um eine Textabfrage mit einem Hinweistext zu erzeugen.
Dies wird z.B. bei der Abfrage der IP-Adresse des Servers verwendet.
6.2.3.5 DrawingObject
DrawingObject ist eine abstrakte Klasse, die von allen zeichenbaren und Touch-aktiven
Klassen beerbt werden muss. Der TouchHandler arbeitet auf DrawingObject-Datentypen.
In der DrawingObject-Klasse wurden einige Methoden, die unabhängig von der Art des
Objektes gültig sind, implementiert. Hierunter zählen unter anderem die „getter― und „setter― der Manipulationsdaten sowie Zoom, Move etc.
Hierbei ist außerdem zu beachten, dass Grafiken neu berechnet werden müssen, wie in
der Methode „rotateImage― zu erkennen ist. Zur Rotation werden die „TranslateTransform―- und die „RotateTransform―- Methode der durch .NET zur Verfügung gestellten
„Graphics-Klasse― verwendet.
6.2.3.5.1 Spielfeld
Das Spielfeld beerbt die DrawingObject -Klasse und muss entsprechend die abstrakten
Methoden implementieren wie z.B. Paint und ResetObject. Bei C# muss eine überschreibende Methode mit dem Schlüsselwort „override― attributiert werden.
6.2.3.5.2 Spielstein
Der Spielstein beerbt, genau wie das Spielfeld, auch die DrawingObject-Klasse und muss
ebenfalls die entsprechenden abstrakten Methoden implementieren.
6.2.3.6 Sound
Audiodateien zu öffnen und abzuspielen. Als Grundlage dient die DLL winm.dll, die viele
verschiedene Formate unterstützt.
6.2.3.7 TouchHandling
Die Klasse TouchHandling enthält die komplette Verarbeitung von Multitouch-Ereignissen.
Dazu gehört die Selektion des richtigen Objektes sowie dessen Manipulation.
Kapitel: TicTacToe
In der Sound-Klasse ist die Logik für das Abspielen von Sounds enthalten. Es ist möglich
40
6.2.3.8 InertiaParam
Die Klasse dient zur Berechnung der Beschleunigung eines Objektes nach dem TouchUpEreignis. So bewegt sich das ausgewählte Objekt noch weiter fort, verlangsamt sich jedoch mit der Zeit, bis es vollständig zum Stillstand gekommen ist.
6.2.3.9 NetworkListener
Die NetworkListener-Klasse dient zum Abhören des Netzwerkverkehrs einer bestimmten
Verbindung. Die Klasse ist als Thread umgesetzt, um nicht den Hauptthread des Programms zu blockieren. Sobald Daten empfangen werden, wird im Hauptthread ein Erei gnis ausgelöst, in dem die Verarbeitung stattfindet.
6.2.3.10
NetworkServer
Die NetworkServer-Klasse dient dem Aufbau einer Netzwerk-Verbindung per TCP. Dabei
wird aktiv auf eine eingehende Verbindung gewartet. Um die Interaktion zum Hauptpro-
Kapitel: TicTacToe
zess nicht zu blockieren, ist diese Klasse ebenfalls als Thread umgesetzt.
41
6.2.4 Use-Case Diagramm
Kapitel: TicTacToe
Abb. 20: Use-Case Diagramm
42
7 Probleme bei der Implementierung
Wie bei jedem Projekt, gab es auch in diesem einige Probleme bei der Implementierung.
Im Folgenden werden ein paar größere Probleme vorgestellt, dessen Lösungen viel Zeit in
Anspruch genommen haben.
7.1 CPU – Auslastung
Als Hintergrundbild wird im Programm ein externes Bild eingesetzt, dessen Größe automatisch an die Fenstergröße angepasst wird. In der ersten Implementierung wurde dafür
das „BackgroundImageLayout― auf Stretch gesetzt, sodass kein Programmieraufwand nötig war. Dieses Attribut führte jedoch zu stark überhöhter CPU-Auslastung, da anscheinend das Bild bei jedem Zeichenvorgang neu skaliert wurde. Daher wird dieses Attribut in
der finalen Version nicht mehr genutzt. Nun wird das Hintergrundbild bei Änderungen der
Fenstergröße manuell neu skaliert. Nach dieser Äderung war die CPU-Auslastung weiterhin leicht erhöht. Der Grund dafür ist die Animation (der Pfeil), die im Hintergrund der Anwendung läuft. Dies ist eine GIF-Animation, die zunächst durch eine ImageBox eingebunden wurde. Diese ImageBox wurde dann durch eine PictureBox ersetzt, welche wesentlich
besser und ressourcenschonender mit einer GIF-Animation umgeht.
7.2 Netzwerkverzögerung
Die Darstellung des Spielfeldes bei dem Spieler, der zum aktuellen Zeitpunkt nicht das
Netzwerk empfangen hat, bestimmt. Hierbei kam es zu starken Verzögerungen. Aufgrund
der hohen CPU – Auslastung vermuteten wir, dass die TCP-Connection nicht schnell genug die Manipulationsdaten sendet, da diese einen Stream verwendet, welcher bekanntermaßen gepuffert ist und lediglich bei geringer Auslastung bzw. Überfüllung geleert wird.
Das Problem hat sich allerdings durch das Aufrufen der Flush Methode des Streams nicht
verbessert. Es stellte sich heraus, dass in C# NetworkStreams ungepuffert sind und der
Aufruf von Flush keinen Effekt hat. 4 Das Problem lag am Absender der Daten über das
Netzwerk, da diese erst gesendet wurden, wenn die Manipulation fertiggestellt wurde.
4
Siehe http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.flush.aspx
Kapitel: Probleme bei der Implementierung
Spielfeld kontrolliert, wird auf Basis von Manipulationsdaten, die dieser Spieler über das
43
Durch das Einbinden der Netzwerkübertragung bei jedem Manipulationsschritt konnte dieses Problem behoben werden. Zum Finden des Fehlers haben wir wie in unter 6.2.2.4 beschrieben eine Netzwerkzeitmessung eingebaut und haben keine Geschwindigkeitsprobleme feststellen können. Wir stießen jedoch auf den nächsten Fehler, dass bei einem geöffneten Popup die Anwendung im Hintergrund nicht weiter läuft. Daraus resultiert, dass,
wenn das Ergebnis einer Zeitmessung angezeigt wird, eine weitere Messung erst abgeschlossen ist, wenn das Popup-Fenster geschlossen wird.
7.3 Blockieren des Anwendungsfensters bei aktiven Popupboxen
Eine Visual-C# Anwendung wird angehalten, wenn eine PopupBox geöffnet ist. D.h. ein
Popup darf nur verwendet werden, wenn das Programm, solange das Popupfenster offen
Kapitel: Probleme bei der Implementierung
ist, angehalten werden darf.
44
8 Fazit
In dieser Ausarbeitung ist ein Multitouch-Tutorial enthalten, in dem wesentliche Programmieraspekte von Multitouch i n der Programmiersprache Visual C++ dargestellt werden. Es
ist genau beschrieben, welche Schritte erforderlich sind, um die Nutzung von MultitouchBibliotheken zu ermöglichen und verschiedene Arten von Touch-Ereignissen zu erkennen
und zu verarbeiten. Das entstandene Programm lässt bereits verschiedene Manipulationen an einem Objekt zu. Neueinsteiger dürften mit diesem Tutorial ohne Probleme selbst
Anwendungen auf diesem Gebiet erstellen können. Einzig Kenntnisse der Sprache Visual
C++ sind von Vorteil.
Als weiterer Teil dieses Laborprojektes ist das Spiel TicTacToe als ein Anwendungsbeispiel in der Programmiersprache C# umgesetzt worden. Dies besitzt eine verbesserte
Physik-Engine gegenüber dem Programm aus dem Tutorial. Neben der Nutzung von Multitouch sind darin auch andere programmiertechnisch wichtige Methoden vorhanden, wie
z.B. die Nutzung der Netzwerkschnittstellen und das Abspielen von Audiodateien. Damit
bietet das Programm einen kleinen Einblick in die vielen audiovisuellen Möglichkeiten von
Multitouch-Anwendungen.
Multitouch ist eine zukunftsweisende Technologie und gewinnt in immer mehr Bereichen
an Bedeutung. Daher können auf die Resultate dieser Arbeit größere Projekte aufgebaut
werden, welche Multitouch nutzen. Die aktuelle Nutzungsmöglichkeit von zwei Erkennungspunkten im Multitouch, soll in Zukunft noch erhöht erweitert werden. So plant Microsoft einen auf das kommende Betriebssystem Windows 8 zugeschnittenen PC mitsamt
5
Vgl. Quelle (7)
Kapitel: Fazit
Touchdisplay, der mindestens fünf Erkennungspunkte hat.5
45
9 Literaturverzeichnis
1. Microsoft. Windows Touch Gestures Overview (Windows). MSDN. [Online] 2. 6 2010.
[Zitat vom: 13. 6 2010.] http://msdn.microsoft.com/dede/library/dd940543%28v=VS.85%29.aspx.
2. —. Architectural Overview. MSDN. [Online] Microsoft, 10. 5 2010. [Zitat vom: 23. 5
2010.] http://msdn.microsoft.com/en-us/library/dd371413%28v=VS.85%29.aspx.
3. —. Download details: Windows 7 Training Kit For Developers. Microsoft. [Online] 22. 10
2009. [Zitat vom: 17. 4 2010.]
http://www.microsoft.com/downloads/details.aspx?FamilyID=1c333f06-fadb-4d93-9c80402621c600e7&displaylang=en.
4. —. Multitouch | Windows 7 Online Training | Learn | Channel 9. MSDN. [Online] [Zitat
vom: 19. 5 2010.] http://channel9.msdn.com/learn/courses/Windows7/Multitouch/.
5. —. NetworStream.Flush Method (System.Net.Sockets). MSDN. [Online] [Zitat vom: 17.
6 2010.] http://msdn.microsoft.com/enus/library/system.net.sockets.networkstream.flush.aspx.
6. Otter, Dieter. vb@richv - API-Referenz - mciSendString-Funktion. vb@rchiv. [Online] 2.
4 2002. [Zitat vom: 11. 4 2010.] http://www.vbarchiv.net/api/api_mcisendstring.html.
7. Chapman, Stephen. Windows 8 Plans Leaked: Numerous Details Revealed | Windows
8, Windows Phone, Office 15 | Stephen Chapman @ MSFTKitchen. Microsoft Kitchen.
[Online] 28. 6 2010. [Zitat vom: 30. 6 2010.] http://msftkitchen.com/2010/06/windows -8-
Kapitel: Literaturverzeichnis
plans-leaked-numerous-details-revealed.html.
46
Herunterladen