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