V03 Laden und Initialisieren der Grafiken - Grafiken des Spiels laden und testweise auf dem Bildschirm anzeigen - eine Klasse anlegen, die alle erforderlichen.

Slides:



Advertisements
Ähnliche Präsentationen
DVG Dateien Dateien. DVG Dateien 2 Die Klasse File Die Klasse File stellt die Verbindung zwischen dem Filesystem des Rechners und dem.
Advertisements

Funktionen.
VO2 Laden und Initialisieren der Sounds. Wir wollen Sounds in unsere Applikation laden Menü erweitern –um den Menüpunkt Sound –mit dem Identifier ID_ULTRIS_SOUND.
Ultris Version 8: Erzeugen der Formen und Anzeigen der Vorschau
Ultris V10 Bewegen, Drehen und Kollisionserkennung.
V11 Auflösen der Formen und Abräumen der Reihen. Zwei neue Methoden ___________________________________ class ultris { private: … void aufloesen(); void.
Java: Dynamische Datentypen
Indirekte Adressierung
Java: Referenzen und Zeichenketten
Strukturen. In einer Struktur kann eine beliebige Anzahl von Komponenten (Daten) mit unterschiedlichen Datentypen (im Gegensatz zu Feldern) zusammengefaßt.
Ein Beispiel in Java.
Dynamischer Speicher und Struktur
Klassenvariable. Da man für jede Kuh bzw. jede Henne auf dem Markt den gleichen Preis für ein Liter Milch, bzw. den gleichen Preis für ein Ei bekommt,
Konstruktoren.
Objekte werden als Adressen (Referenzen) übergeben. Dies führt manchmal zu unerwarteten Ergebnissen...
Polymorphie (Vielgestaltigkeit)
Polymorphie (Vielgestaltigkeit)
Objekte und Arbeitsspeicher
V AdresseWert public static void main(...){ int[] v; v=new int[2]; } Was veranlasst diese Anweisung im Arbeitsspeicher ? Es wird im Arbeitsspeicher.
Dynamischer Speicher. In einer Funktion wird z.B. mit der Deklaration int i; Speicher auf dem sogenannten Stack reserviert. Wenn die Funktion verlassen.
V10: Bewegen der Formen und Kollisionserkennung Steuerung der Spielsteine durch Tastenbefehle (Übersicht der Befehle unter der Hilfe)
V09 Fallende Formen, Geschwindigkeitsregelung und Timing Daniel Ebner Spieleprogrammierung mit DirectX und C++
Softwaretechnologie II WS 08/09 SpieleProgrammieren UlTris V07 Reihen vorbelegen, Spielfeld anzeigen und Punktestand ausrechnen Sibylle C. Schellhorn,
Vers. 6: Der Konfigurationsdialog Quelle: Spieleprogrammierung mit DirectX und C++, U. Kaiser und P. Lensing, Galileo Computing (2007)
Spieleprogrammierung mit DirectX und C++
V03 Laden und Speichern von Spielfeldern und der Spielfeldeditor.
V11 Auflösen der Formen Abräumen der Reihen. Erweiterung der Klasse ultris class ultris { private: … void aufloesen() void aufruecken() public: … }
Praktikum Entwicklung und Einsatz von Geosoftware I - Sitzung 3 Klassen, Objekte, Arrays und Kontrollstrukturen Sommersemester 2003 Lars Bernard.
Universität Dortmund, Lehrstuhl Informatik 1 EINI II Einführung in die Informatik für Naturwissenschaftler und Ingenieure.
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
EINI-I Einführung in die Informatik für Naturwissenschaftler und Ingenieure I Vorlesung 2 SWS WS 99/00 Gisbert Dittrich FBI Unido
Java-Kurs Grafik Julian Drerup.
Programmieren mit JAVA
Programmieren mit JAVA Teil V. Grafikausgabe mit JAVA, das AWT Java wurde von Anfang an mit dem Anspruch entwickelt, ein vielseitiges, aber einfach zu.
PKJ 2005/1 Stefan Dissmann Methoden (Motivation) Idee: Identische Programmabschnitte zusammenfassen und mit einem Namen versehen Vorteile: Übersichtlichkeit.
PRJ 2007/1 Stefan Dissmann Motivation Problem: gleiche Datenstrukturen werden für verschiedene Objekte gebraucht: z.B. Listen von Studierenden, Kunden,
PKJ 2005/1 Stefan Dissmann Ausblick Es fehlen noch: Möglichkeiten zum Strukturieren größerer Programme Umgang mit variabler Zahl von Elementen Umgang mit.
Zusammenfassung Vorwoche
PKJ 2005/1 Stefan Dissmann Zusammenfassung Vorwoche Methoden sind mit einem Namen versehene Programmabschnitte besitzen Rückgabetyp, Namen, Parameterliste.
1DVG3 - Paint Paint ein Zeichenprogramm. DVG3 - Paint 2 Paint – ein Zeichenprogramm.
DVG Klassen und Objekte
Wir müssen also überlegen: Implementierung der Knoten, Implementierung der Kanten, daraus: Implementierung des Graphen insgesamt. Annahme: die Knoteninhalte.
Einführung MySQL mit PHP
3D Programmierung Version 12 - Highscores. Die vom Spieler erzielte Punktzahl wird mit 5 vorgegebenen Punktzahlen verglichen und, falls nötig, in die.
Java ohne Kara. Java ohne Kara Ab jetzt: Java ohne Kara Ziel: Erfahrungen sammeln mit ersten Java Programmen.
Einführung in die Programmiersprache C 3.Tag Institut für Mathematische Optimierung - Technische Universität Braunschweig.
Javakurs FSS 2012 Lehrstuhl Stuckenschmidt
EPROG Tutorium Einheit 4 Klassen und Objekte. Wiederholung Schleifen do... while while for break/continue Strings String char Methoden für Strings Arrays.
Von der Planung bis zum Hauptmenü Seminar: Softwaretechnologie II Dozent: Prof. Manfred Thaller Referent: Jan Bigalke.
Einführung in die Programmierung Wintersemester 2008/09 Prof. Dr. Günter Rudolph Lehrstuhl für Algorithm Engineering Fakultät für Informatik TU Dortmund.
Javakurs FSS 2012 Lehrstuhl Stuckenschmidt
Vom Umgang mit Daten. public void myProgram() { int[] saeulenWerte = new int[world.getSizeX()]; for (int i = 0; i < saeulenWerte.length; i++) { saeulenWerte[i]
Aufgaben Version 1: Es soll eine Wetterstation mit folgenden zwei Anzeigen implementiert werden: Aktuelle Wetterbedingungen mit Temperatur und.
Programmierpraktikum Java SS 2005
EPROG Tutorium #3 Philipp Effenberger
Inf K1/2 Sj 13/14 GZG FN W.Seyboldt 1 SFZ FN Sj. 13/14 Python Klassen und Objekte.
A Workshop About this chapter General description Units Time Schedule
Java-Kurs Übung Besprechung der Hausaufgabe
Funktionen. Aufgabe : Eingabe zweier Zahlen ---> Minimum bestimmen Dann nochmals Eingabe zweier Zahlen ---> Minimum bestimmen.
Pointer. Grundsätzliches: Im Arbeitsspeicher werden Daten gespeichert. Um auf die Daten eindeutig zugreifen zu können, werden diesen Daten Adressen zugeordnet.
Funktionen, Felder und Parameter- übergabe. Funktionsaufruf mit Feld als Parameter: Parameter = Name des Feldes.
Tutorium Software-Engineering SS14 Florian Manghofer.
Tutorium Software-Engineering SS14 Florian Manghofer.
Tutorium Software-Engineering SS14 Florian Manghofer.
C++ FÜR cOMPUTERSPIELENTWICKLER
Tutorium Software-Engineering SS14 Florian Manghofer.
Ein Spiel mit der SDL - Teil I. Ein Spiel mit der SDL  kostenlose Bibliothek – Simple DirectMedia Layer Grafik darstellen Benutzereingaben abfragen Sounds.
Konstruktoren.
Java-Kurs Übung Grafik in Java - das Abstract Windowing Toolkit
Implementieren von Klassen
 Präsentation transkript:

V03 Laden und Initialisieren der Grafiken - Grafiken des Spiels laden und testweise auf dem Bildschirm anzeigen - eine Klasse anlegen, die alle erforderlichen Grafikoperationen enthält: class display - unter Rückgriff auf definierte Klassen CDisplay und CSurface in Ddutil.h und Ddutil.cpp - CDisplay: - allgemeine Schnittstelle zum Grafiksystem - stellt übergreifende Dienste bereit - CSurface: - Instanzen nehmen einzelne darzustellende Bitmaps auf - Elemente der Oberfläche werden aus Bitmap - Datei in Klasse CSurface eingelesen

CDisplay: Funktionen von Interesse class CDisplay { public: HRESULT CreateWindowedDisplay; // erzeugt ein Display in einem Fenster HRESULT CreateSurfaceFromBitmap(...); // erzeugt eine Surface aus einer Bitmapdatei HRESULT Blt(...); // kopiert eine Surface in das Display HRESULT Present(); // aktualisiert Display im Fenster LPDIRECTDRAW7 GetDirectDraw(); // gibt Zeiger auf das mit Display verbundene DirectDraw - Objekt zurück HRESULT UpdateBounds(); // aktualisiert Display bei Größenänderung des Fensters };

CSurface: Funktionen von Interesse class CSurface { HRESULT DrawBitmap(); }; - Funktion überträgt eine Bitmap aus einer Datei in eine Surface bzw. Oberfläche

1. Schritt -Klasse display wird mit dem CDisplay versehen und mit erforderlichen Oberflächen bzw. Csurfaces -hinzu kommen Konstruktor display und Destruktor ~display und eine Freigabefunktion namens free_all class display { private: CDisplay dsply; CSurface *hgrnd;// Zeiger auf ein CSurface CSurface *fldst; CSurface *fllst; CSurface *prvst; CSurface *deckel; CSurface *ziff [10]; public: display ();// Initialisierung der Zeiger mit 0 void free_all();// gibt Speicher frei ~display() { free_all(); }// Aufruf von Freigabefunktion };

Konstruktor: alle Zeiger werden mit 0 initialisiert display::display () { int i; hgrnd = 0; fldst = 0; fllst = 0; prvst = 0; deckel = 0; for ( i = 0; i < 10; i++) ziff [i] = 0; }

free_all wird vom Destruktor aufgerufen und beseitigt alle dynamisch angelegten Objekte, d.h. gibt Speicher frei void display :: free_all () { int i; if (hgrnd) delete hgrnd; if (fldst) delete fldst; if (fllst) delete fllst; if (prvst) delete prvst; if (deckel) delete deckel; for (i = 0; i < 10; i++) { if ( ziff [i] ) delete ziff [i];} }

2. Schritt -Hinzufügen einer Initialisierungsmethode -erzeugt Display und Surfaces -Initialisierung des Displays durch die Funktion CreateWindowedDisplay -diese übernimmt den Handle des umschließenden Fensters (wnd) und die gewünschten Abmessungen des Displays (ultris_nettobreite, ultris_nettohoehe) -Zur Erinnerung: HWND ultris_window -Handle; Zeiger, der Zugriff auf Hauptfenster ermöglicht; in WinMain Funktion class display { private:... public:.. HRESULT init (HWND wnd); };

HRESULT display :: init (HWND wnd) { HRESULT hr; // Fehlercode hr,erfolgt Rücksprung in aufrufendes Programm int i; char fname[20]; hr = dsply.CreateWindowedDisplay (wnd, ultris_nettobreite, ultris_nettohoehe); if (hr < 0) return hr; hr = dsply.CreateSurfaceFromBitmap (&hgrnd, ul_hgrnd.bmp, ultris_nettobreite, ultris_nettohoehe); if (hr < 0) return hr; hr = dsply.CreateSurfaceFromBitmap (&fldst, ul_feld.bmp, 20, 20); if (hr < 0) return hr; hr = dsply.CreateSurfaceFromBitmap(&fllst, ul_stein.bmp, 20, 20);

if (hr < 0) return hr; hr = dsply.CreateSurfaceFromBitmap (&prvst, ul_prev.bmp, 15, 15); if (hr < 0) return hr; hr = dsply.CreateSurfaceFromBitmap (&deckel, ul_adeck.bmp, 240, 100); if (hr < 0) // überprüft ob bei Erzeugung Fehler aufgetreten return hr; // Rücksprung in aufrufendes Programm for (i=0; i < 10; i++) { sprintf (fname, ul_z%d.bmp, i); hr = dsply.CreateSurfaceFromBitmap ( &ziff[i], fname, 20, 40); if (hr < 0) return hr; } return S_OK; }

hr = dsply.CreateSurfaceFromBitmap (&fldst, ul_feld.bmp, 20, 20); if (hr < 0) return hr; -einzelne Surfaces werden durch Aufruf der Funktion CreateSurfaceFromBitmap dynamisch aus jeweiliger Bitmap - Datei erzeugt -als Parameter übergeben: -Adresse eines Zeigers, in dem Referenz auf Surface abgelegt wird -Name der Bitmap - Datei -Abmessung (Breite, Höhe) der Bitmap -tritt bei Erzeugung eines Elements ein Fehler auf -Fehlercode hr - erfolgt Rücksprung in aufrufendes Programm -ein Surface entspricht einer Bitmap

Kontinuierlich wirkende Animation für das menschliche Auge - Kinofilm besteht aus Folge von Standbildern -in der Abfolge der Standbilder eine Frequenz von mehr als 20 Bildern bzw. Frames pro Sekunde = Eindruck einer kontinuierlichen Bewegung - unser Display hat Front- und Backbuffer - im Frontbuffer: befindet sich Bild, das gerade angezeigt wird - im Backbuffer: neues Bild, das heißt den nächsten Frame aufbauen -zur Darstellung des nächsten Frames - umschalten zwischen Front- und Backbuffer - zwei benötigte Funktionen: - Funktion um Surfaces in den Backbuffer des Displays zu laden ( Blt) - Funktion um zwischen Front- und Backbuffer umzuschalten (Present)

1. Funktion Blt = Abkürzung für Blocktransfer -Bitmap einer Surface (Quellsurface) an bestimmte Position des Displays (Zielbereich) transferieren oder blitten HRESULT CDisplay::Blt (DWORD x, DWORD y, CSurface * pSurface, RECT* prc) HRESULT CDisplay::Blt (x - Koordinate des Zielbereichs, y- Koordinate des Zielbereichs, Quell - Surface, ausgewähltes Rechteck der Quell Surface (kann fehlen)) -wenn kein Teilrechteck (prc) angegeben wird,so wird die gesamte Bitmap geblittet 2. Funktion zum Umschalten zwischen Front- und Backbuffer HRESULT CDisplay::Present()

Blt - Methoden class display { private:... public:... void hintergrund () {dsply.Blt (0, 0, hgrnd);} // hintergrund beginnt an Position (0,0), füllt gesamten // Fensterinhalt, Csurface ist hgrnd void abdeckung () {dsply.Blt (60, 0, deckel); } // abdeckung beginnt an stelle (60,0), void ziffer (int pos, int val) {dsply.Blt (120+pos*20, 50, ziff [val] );} // Zifferndarstellung beginnt bei 120, deshalb 120+ // eine Ziffernabbildung ist 20 Pixel breit // int pos ist Index der Ziffer // int val entscheidet über Art der Bitmap void feldstein (int z, int s) {dsply.Blt (80+s*20, 100+z*20, fldst);} // Segment eines gefallenen Steins liegt in einer Zeile z und Spalte s // Feld beginnt bei x = 80 und y = 100 // Zeilen- und Spaltenbreite beträgt jeweils 20 Pixel // Koordinaten berechnen sich daher x = 80+s*20 und y = 100+z*20

void fallstein (int z, int s, int offset){ dsply.Blt (80+s*20, 100+z*20+offset, fllst);} // fallendes Steinsegment in Spalte s, jedoch nicht in Zeile, // da es Pixel für Pixel fällt // zu der letzten Zeile z kommt Zugabe offset, um die das // Segment weiter gerückt ist // Offset = Anzahl von Pixeln, die sich Stein n.u. bewegt hat void prevstein (int p, int z, int s, int b, int h) { dsply.Blt (290+s*15+(4-b)*15/2, 410-p*70+z*15+(4-h)*15/2, prvst);} // Berechnung der Position der Vorschausteine // Steine sollen in Ausgabe zentriert dargestellt werden // es gibt bis zu fünf Vorschausteine p = 0,1,2,3,4 // linke obere Ecke: x = 290 und y = 410-p*70 /* bei Segmentgröße von 15 x 15 Pixeln liegt die linke obere Ecke eines Segments in Spalte s und Zeile z bei x = 290+s*15 und y = 410-p*70 + z*15 */ /* wenn Anzahl der Segmente des Steins in Höhe h und Breite b bekannt ist, kann man den Randausgleich berechnen, wenn Stein in 4 x 4 Segmente großen Vorschaubereich */ /* man erhält Koordinaten: x = 290+s * 15 + (4-b)*15/2 und y = p*70+z*15+(4- h) * 15/2 */ };

Spieloberfläche Ziffernbereich Deckel Fallfläche Hintergrund Vorschau

Funktion HRESULT present (); -Grafiken aus dem Backbuffer auf den Bildschirm bringen -Phänomen der Lost Devices: Zugriff auf Devices wie die Grafikkarte kann verloren gehen -> Device befindet sich dann im lost state -Grafikoperationen, die nur auf internen Speicher zurück greifen, wie etwa das Blitten, werden fehlerfrei durchgeführt -jedoch wird bei Umschalten von Front- und Backbuffer der lost state kritisch, da jetzt auf Grafikkarte zugegriffen werden muss -Returncode für Fehlermeldung: DDERR_SURFACELOST -verlorene Daten auf Grafikkarte müssen restauriert werden: dies macht Funktion restore

Funktion HRESULT present () -zunächst Ausführen der Present Funktion von CDisplay -sollte das misslingen, weil der Fehlercode übergeben wird, so werden die Surfaces restauriert HRESULT display::present() { HRESULT hr; hr = dsply.Present(); if ( hr == DDERR_SURFACELOST )//fehlercode return restore(); return hr; }

Funktion HRESULT restore(); -restaurieren aller Surfaces des Displays -neuzeichnen aller Bitmaps in Surfaces HRESULT display::restore() {HRESULT hr; int i; char fname[20]; hr = dsply.GetDirectDraw() -> RestoreAllSurfaces(); if (hr < 0) return hr; hr = hgrnd->DrawBitmap (ul_hgrnd.bmp, ultris_nettobreite, ultris_nettohoehe); if (hr < 0) return hr; hr = fldst -> DrawBitmap (ul_feld.bmp, 20,20); if...fllst, prvst, deckel... for ( i = 0; i < 10 ; i++) {sprintf (fname, ul_z%d.bmp, i); hr = ziff [i] -> DrawBitmap (fname, 20, 40); if ( hr < 0) return hr;} return S_OK;}

zum Abschluss zwei weitere Member - Funktionen... class display { private:... public:.. void update () { dsply.UpdateBounds();} HRESULT cooperative (){ return dsply.GetDirectDraw() -> TestCooperativeLevel ();} }; -Memberfunktion update:Aufruf, wenn die Lage unseres Hauptfensters auf Bildschirm verändert ist -es geschieht Aufruf der Methode UpdateBounds, die Display an die neue Lage anpasst -Memberfunktion cooperative: stellt Kooperativität des Displays fest

-Klasse display ist jetzt vollständig implementiert, wir legen Instanz dieser Klasse mit dem Namen ultris_display an display ultris_display; - Objekt muss zum Schluss in Windows Applikation integriert werden -innerhalb WinMain Funktion Display initialisieren bevor Fenster mit ShowWindow dargestellt wird int APIENTRY WinMain (...) {... if (ultris_display.init (ultris_window) < 0) { // wenn Initialisierung fehl schlägt, Abbruch // der Anwendung mit Fehlerdialog MessageBox (ultris_window, Fehler beim Initialisieren der Grafik, Ultris - Fehlermeldung, MB_OK | MB_ICONERROR | MB_SETFOREGROUND); return 0; } // sonst geht es mit Anzeige des Fensters // und Main Event Loop weiter ShowWindow (ultris_window, nCmdShow); while (TRUE){...} }

Callback - Handler unseres Hauptfensters ultris_windowhandler -immer wenn Fenster bewegt oder in seiner Größe verändert wurde, erhalten wir eine Benachrichtigung durch die Nachricht WM_MOVE -als Reaktion rufen wir die update Funktion unseres Display auf LRESULT CALLBACK ultris_windowhandler (... ) { switch (msg) {... case WM_MOVE: ultris_display.update(); return 0; case WM_PAINT: int i; ultris_display.hintergrund(); ultris_display.abdeckung();

for (i = 0; i< 6; i++) ultris_display.ziffer (i, i+1); for (i = 0; i < 10; i++) ultris_display.feldstein (19-i, i); for (i = 0; i < 10;i++) ultris_display.fallstein ( 1, i, 2*i); for ( i = 0; i < 4; i++) ultris_display.prevstein ( 3, 0, i, 4, 1); ultris_display.present (); break; }... } -hier wird message - orientierte Architektur des Windows - Systems deutlich -Fensterausgaben dürfen nicht spontan gemacht werden -System fordert zum Neuzeichnen des Hauptfensters mit Message WM_PAINT auf -wenn diese Message erkannt wird, werden einige Testausgaben gemacht: Hintergrund, Abdeckung, einige Ziffern und Steine

Funktion WinMain -an die Stelle, in der regelmäßig wiederkehrende, das Spiel betreffende Aktivitäten eingebaut werden können, gelangt man immer dann, wenn keine Windows - Message vorliegt -hier kann also der Spielverlauf programmiert werden -zudem: regelmäßiges Prüfen der Devices und der Kooperativität int APIENTRY WinMain (...) { while (TRUE) { if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {...} else { HRESULT hr; hr = ultris_display.cooperative(); // Prüfen der Kooperativität // wenn der Aufruf der Funktion ein negatives Ergebnis // liefert, so liegt ein Problem vor if (hr < 0) {

switch (hr) { case DDERR_EXCLUSIVEMODEALREADYSET: // eine andere Anwendung hat sich Grafik Device exklusiv // gesichert Sleep (10);//warten bis es frei gegeben wird break; case DDERR_WRONGMODE: // jemand hat Grafikmodus (etwa die Auflösung) geändert // in dieser Situation muss alles noch einmal neu // initialisiert werden // zuvor belegte Ressourcen frei geben ultris_display.free_all(); ultris_display.init (ultris_window); PostMessage (ultris_window, WM_PAINT, 0, 0); // hier Message WM PAINT schicken zum Neuzeichnen des Fensters break; } else{// hier kann Spiel stehen} }

-Es gibt weitere Meldungen im Zusammenhang mit Grafikkarte, auf die man reagieren kann -Wenn das System im 8 -Bit -Grafikmodus ist (256 Farben), arbeitet die Grafikkarte mit Farbpalette -Das heißt, auch die Farbpalette muss neu initialisiert werden, wenn sie durch andere Anwendung überschrieben wurde -Entsprechende Message: WM_QUERYNEWPALETTE -Wir verwenden jedoch für Ultris Bitmaps mit mehr als 256 Farben

Kurz zurück zum Blitten - -es ist auch möglich statt rechteckiger Objekte andersformige Objekte zu blitten -Dies geschieht unter Verwendung des Color Keying -Eine in der darzustellenden Bitmap nicht vorkommende Farbe wird als Color Key für die Surface ausgewählt -Alles, was in Color Key Farbe in der Bitmap vorkommt, wird nicht transferiert -Equivalent: Blue Box im Fernsehen -Beispiel: Bitmap liegt in einer Datei vor, alles, was nicht gezeichnet werden soll, ist schwarz -Anlegen einer Surface: CSurface *s -Initialisieren der Surface mit CreateSurfaceFromBitmap -Color Key wird duch Funktionsaufruf gesetzt: s -> SetColorKey (RGB (0, 0, 0)); - schwarze Bildpunkte werden nicht transferiert

... Vielen Dank!!