Toegift

Pengo © 2002-2003, Joost Ronkes Agerbeek

Eén toegift? Ik zie er wel drie!

We zijn klaar met Pengo, maar is Pengo af? Je kunt natuurlijk altijd wel verbeteringen bedenken. Ik heb de code zo opgezet dat je zelf makkelijk uitbreidingen kunt toevoegen. In deze les zal ik een aantal van die uitbreidingen bespreken.

De stof in deze les is niet verplicht. Je krijgt er geen vragen over op je toets en je hoeft het niet toe te passen tijdens het project. Er is maar één reden om deze les te maken en die reden is duidelijk: omdat programmeren leuk is. :-)

De onderwerpen die ik hier behandel, zal ik niet zo ver uitwerken als ik dat voorheen heb gedaan. Je zult dus af en toe zelf code moeten schrijven. Dat heb je in het eerste semester ook wel eens gedaan, weet je nog? :-P

Geluid

Hoor jij dat ook? Niet? Dat zou goed kunnen, want Pengo is op dit moment helemaal stil. Gelukkig is het niet zo moeilijk om dat op te lossen. Je hebt nodig: een paar .wav-bestanden en de functie PlaySound. O ja, je moet windows.h includen.

De functie PlaySound accepteert drie parameters: de bestandsnaam van het .wav-geluid, een parameter die wij altijd op 0 zetten en een paar opties. Op die opties kom ik zo terug. Stel dat je een geluid wil afspelen telkens als Pengo tegen een blok aanschopt. De code is dan als volgt. (Je moet natuurlijk een bestand kick.wav in je projectmap hebben staan.)

// speel geluid
PlaySound("Kick.wav", NULL, SND_ASYNC | SND_FILENAME);

Simpel, nietwaar? Nog even over de twee opties. SND_FILENAME geeft aan dat het geluid uit een bestand willen laden. Een andere optie is om Windows- resources te gebruiken, maar dat maakt de uitleg nodeloos lang. SND_ASYNC vertelt Windows om het geluid asynchroon af te spelen. Dat betekent dat het programma doorloopt terwijl het geluid speelt. Als je SND_ASYNC vervangt door SND_SYNC moet je telkens wachten totdat het geluid klaar is voordat je verder kunt met Pengo.

[ Naar boven | Terug naar Pengo ]

Achtergrondmuziek

Een gezellig muziekje op de achtergrond is natuurlijk ook niet weg. Probleem is, we spelen een geluid nu maar één keer af, maar de bedoeling is dat we een geluidsfragment loopen. We kunnen niet in de game loop telkens PlaySound aanroepen, want dan beginnen we niet op het juiste moment opnieuw met het geluid. We moeten dus eerst berekenen hoe lang het geluidsfragment is. Vervolgens moeten we telkens wachten totdat het klaar is met spelen. Dit alles moet op de milliseconden nauwkeurig anders stottert de muziek. O jee. :-s

Of we gebruiken de optie SND_LOOP. :-) De volgende code zet je voordat de game loop begint.

// start muziek
PlaySound("Pengo.wav", NULL, SND_ASYNC | SND_FILENAME | SND_LOOP);

Als het spel stopt, moet je ook de muziek stilzetten. Dat gaat als volgt.

// stop muziek
PlaySound(NULL, NULL, SND_ASYNC | SND_FILENAME | SND_LOOP);
[ Naar boven | Terug naar Pengo ]

Simultaan geluid

O, o, dat gaat niet helemaal goed. Je kunt nu losse geluiden afspelen en je kunt muziek afspelen, maar niet allebei tegelijk. Zodra je een keer een los geluid afspeelt, stopt je muziek meteen.

Eerlijk gezegd heb ik geen kant-en-klare oplossing voor dit probleem. Een zoektocht op groups.google.com levert het volgende op. Er zijn twee manieren om dit probleem op te lossen: zelf een audio mixer schrijven of DirectSound gebruiken. Beide vind ik te uitgebreid om te beschrijven.

We zouden natuurlijk ook gebruik kunnen maken van... MIDI (horror!). Voorlopig laat ik het probleem maar even rusten. Misschien bedenk ik binnenkort wel een oplossing. Aan de andere kant, misschien ook niet.

[ Naar boven | Terug naar Pengo ]

Transparante bitmaps

Op veler verzoek: de achtergrondbitmap. Pengo speelt zich op dit moment af tegen een zwarte achtergrond. Je kunt natuurlijk ook zelf een achtergrond tekenen en alle bitmaps daar bovenop plakken. Probleem is alleen dat je dan zwarte randen rond je bitmaps krijgt.

De oplossing ligt in het gebruiken van een bitmapmasker. Een bitmapmasker is net zo groot als de bitmap die je gebruikt voor, bijvoorbeeld, de vijand. Het gedeelte waarop de vijand staat, maak je zwart en het transparante gedeelte maak je wit.

Bitmap en bijbehorend bitmapmasker

Let erop dat het transparante gedeelte van de bitmap in de bitmap zelf zwart is. Doe je dit niet, dan gaat het fout.

De bitmap naar het scherm kopiëren gaat nu in twee stappen: eerst kopieer je het masker en vervolgens de bitmap. Uiteraard werkt het niet als je beide plaatjes pixel voor pixel over elkaar heen plakt. Gelukkig heeft de functie BitBlt een extra optie. Hier volgt de code.

// plaats masker in device context
SelectObject(myBitmapDC, myMask);

// teken masker
BitBlt(myWindowDC, 20, 20, 20, 20, myBitmapDC, 0, 0, SRCAND);

// plaats sprite in device context
SelectObject(myBitmapDC, mySprite);

// teken sprite
BitBlt(myWindowDC, 20, 20, 20, 20, myBitmapDC, 0, 0, SRCINVERT);

De truc zit hem in het gebruiken van SRCAND en SRCINVERT. Kijk maar eens wat er gebeurd als je alleen het masker tekent. Overigens, sprite is een ander woord voor bitmap (min of meer). Ik heb het volledige voorbeeld opgenomen in de downloadsectie.

[ Naar boven | Terug naar Pengo ]

Conclusie

Conclusie? Ik ben nog helemaal niet klaar! Ik zal in de loop (nee, nee, dat spreek je niet uit als loep) van de komende weken nog extra onderwerpen toevoegen. In de tussentijd moet mij nog iets van het hart.

Programmeren is leuk! :-)

[ Naar boven | Terug naar Pengo ]

Downloads


Valid XHTML 1.0! Correct CSS! Laatst bijgewerkt: dinsdag 15 april 2014