Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

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

Ähnliche Präsentationen


Präsentation zum Thema: "V03 Laden und Initialisieren der Grafiken - Grafiken des Spiels laden und testweise auf dem Bildschirm anzeigen - eine Klasse anlegen, die alle erforderlichen."—  Präsentation transkript:

1 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

2 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 };

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

4 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 };

5 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; }

6 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];} }

7 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); };

8 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);

9 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; }

10 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

11 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)

12 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()

13 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

14 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 = 410 - p*70+z*15+(4- h) * 15/2 */ };

15 Spieloberfläche Ziffernbereich Deckel Fallfläche Hintergrund Vorschau

16 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

17 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; }

18 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;}

19 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

20 -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){...} }

21 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();

22 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

23 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) {

24 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} }

25 -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

26 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

27 ... Vielen Dank!!


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

Ähnliche Präsentationen


Google-Anzeigen