Programmera spel i C++ för nybörjare/Animation 2
(Genomgången förutsätter att du har en fungerande installation av Microsoft Visual C++ 2010 Express och SFML 1.6 på din dator.)
OBS!!!! Detta är en demonstration av hur en animation visas. Den här koden fungerar INTE inuti ett spel!
Explosioner och enkla animationer
redigeraDen enklaste formen av animation i alla spel är explosionen. Samtidigt är det troligen också den vanligaste animationen. Fördelen med explosionen är att den inte rör på sig. Man behöver bara placera ut den på spelplanen och spela upp den. Här följer ett komplett kommenterat exempel som beskriver hur en animation av en explosion går till. Redan nu vill jag påpeka att den kod som följer här nedanför inte fungerar i ett spel (se nästa kapitel istället) man jag använder den som ett enkelt exempel för hur animationer går till, och den är bra att använda som grund för att synkronisera ljud och bild i animationer i allmänhet.
Vi börjar med att skapa en synnerligen enkel klass, en klass som bara innehåller en sprite - som skall bli vår explosion. I SFML måste man ha en sprite för att ö.h.t. kunna visa upp en bild på bildskärmen.
//Skapa explosionsklassen, så enkel som möjligt class Explosion { public : sf::Sprite Sprite; // en per instans };
När vi sedan låter explosionen synas behöver vi också en funktion för den. Funktionen kan se ut så här:
void pang(float x, float y, Explosion &Klassinstans, sf::Image bildfilsnamn, sf::RenderWindow &App ); //Funktionen som initierar explosionen
- Den heter pang.
- Explosionen skall placeras ut på x,y koordinaterna.
- Den är en instans av Explosion som har en sprite vi använder oss av.
- Bildfilen är den spritemap vi använder för att skapa animationen.
- Renderwindow är det fönster vi visar spelet i.
För enkelhetens skull har jag tagit samma explosions spritemap som i spelexemplet "Space shooter". Du hittar den här:
http://cdn.pimpmyspace.org/media/pms/c/b9/9e/ez/xplosion17.png
Den animationen är 5x5 bildrutor stor där varje ruta är 64x64 pixels.
Main funktionen blir väldigt simpel, det är trots allt bara ett exempel:
#include <iostream> #include <SFML/System.hpp> #include <SFML/Window.hpp> #include <SFML/Graphics.hpp> #define SFML_STATIC //Se till så att det inte behövs extra DLL-filer using namespace std; // utifall att konsollen behövs för felsökning class Explosion { public : sf::Sprite Sprite; // en per instans }; void pang(float x, float y, Explosion &Klassinstans, sf::Image bildfilsnamn, sf::RenderWindow &App ); //Funktionen som initierar explosionen int main (int argc, char *argv) { //main startar //ladda in bild för explosionen sf::Image explosionsbildmap; //explosionens spritemap är 5 x 5 rutor 64x64 pixels stora if (!explosionsbildmap.LoadFromFile("xplosion17.png")) { cout << "Kan inte hitta bilden: xplosion17.png " << endl; } //Skapa en kopia av klassen explosionen Explosion Explosionskopia; sf::RenderWindow App(sf::VideoMode(800, 600, 32), "Test av explosion"); // Skapa fönstret vi skall testa explosionen i while (App.IsOpened()) { //while 1 startar sf::Event Event; //kolla om mus/tangentbord används while (App.GetEvent(Event)) { //while 2 börjar if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape)) App.Close();//avsluta programmet if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Return)) //Visa upp explosionen om man trycker ner return-knappen pang(100, 100, Explosionskopia, explosionsbildmap, App); //Slutligen visar vi upp ändringarna om och om igen många gånger i sekunden App.Clear(sf::Color(0, 100, 0)); //rensa allt i fönstret och ersätt med grönfärg App.Display(); //visa upp ändringarna för användaren } //while 2 slutar } //while 1 slutar } //main slutar
Vad är det som händer? När vi trycker ner return/enter tangenten ritas en explosion ut på koordinaterna 100,100. Kordinaterna kan bytas ut och det kan naturligtvis vara vad som helst i programmeringen av ett spel som avgör om funktionen skall användas. Det som är intressant är själva koden till funktionen:
void pang(float x, float y, Explosion &Klassinstans, sf::Image bildfilsnamn, sf::RenderWindow &App )
vad gör egentligen den?
Explosionsanimation
redigeraFör att kunna skapa en animation i SFML används vanligtvis.
- En spritemap
- En sprite
- En klocka
Det första man måste göra är att beräkna hur stor varje bildruta är. För att exemplet skall fungera måste varje bildruta i animationen vara exakt lika stor. Högerklicka på bilden och välj egenskaper. Då står det bildens totala bredd och höjd. Ta fram en miniräknare och dividera bredden med antalet olika bilder som finns i sekvensen och gör sedan likadant med höjden. Då får du fram varje enskild bildrutas bredd och höjd.
Du måste ha en sprite. SFML är utformat så att du måste ha en sprite för att kunna visa en bild. Kommer du ihåg att t.o.m. bakgrunden i ett spel är en sprite. Detta är speciellt för SFML och open GL.
Om man vill ta fram en speciell del i en spritemap och använda den på en sprite är koden t.ex.:
Sprite.SetSubRect(sf::IntRect(0,0,64,64));
för att visa upp den bild som är längst upp till vänster i spritemapen om bilderna är 64x64 pixels stora. 0,0 är det övre vänstra hörnet i den bild som skall visas upp medan 64,64 (i exemplet) är det nedre högra hörnet på den del av bilden som skall visas upp. Koden fungerar enbart på fyrkantiga bildrutor.
Du måste ha en klocka som avgör när vi skall hoppa till nästa bildruta. Animationsföljden blir:
- 1: Nollställ klockan och hoppa till första raden
- 2: Ställ dig på första rutan på första raden och visa upp den för spelaren.
- 3: Fortsätt att visa bilden tills tillräckligt mycket tid förflutit. 0.1 till 0.3 sekund kan vara lämpligt.
- 4: Gå till nästa ruta och gör likadant, sedan nästa, sedan nästa tills raden är slut.
- 5: Nollställ klockan. och hoppa till nästa rad
- 6: Repetera alltihop tills det är slut på rader.
Om man också har ett ljud som skall spelas upp till explosionen kan det vara vettigt att beräkna animationens längd i tid utifrån explosionsljudets tid så att de börjar och slutar ungefär samtidigt. I exemplet är det 0.01 sekund mellan varje bild och det är 25 bilder vilket ger en animation på ca 0.25 sekunder. Om ljudet låter längre tid än det kan man alltid redigera om det i ett ljudbehandlingsprogram som "Audacity" och "trycka ihop det" så att det inte låter längre än 0.25 sekunder. Läs längre ner om ljud i detalj.
Om man bakar in den sekvensen i vår funktion kallad pang ser det ut så här:
void pang(float x, float y, Explosion &Klassinstans, sf::Image bildfilsnamn, sf::RenderWindow &App ) { int rutorY = 0; //max 5, bildrutor i y-led // int rutorX = 0; //max 5, bildrutor i x led //Obs, eftersom vi baserar animationen på tid och inte på vilken ruta man står på //behöver vi bara bekymra oss om vilken rad av rutor vi står på. int bildbredd = 64; //varje enskild rutas bredd int bildhojd = 64; //varje enskild rutas höjd sf::Clock ExplosionClock; //Skapa en timer för explosionen float visningstid = 0.01f; //0.01 sekund mellan varje Klassinstans.Sprite.SetPosition(x,y); //Placera ut animationen på rätt plats på spelplanen Klassinstans.Sprite.SetImage(bildfilsnamn); //ge animationen bilden av explosionen ExplosionClock.Reset(); //Se till så att klockan verkligen är 0 while ( rutorY < 5) //Så länge man är på någon rad {//while i y-led while (ExplosionClock.GetElapsedTime() < (visningstid * 5)) //Så länge man är på någon bild i en rad { //while i x-led //Välj ut vilken av de 5 bilderna vi skall ta //Genom att flytta in 64 eller 128 eller 192 osv. //pixlar in på bildkartan if (ExplosionClock.GetElapsedTime() >= 0.0 && ExplosionClock.GetElapsedTime() < visningstid) { bildbredd = 64; //Gå till första bilden } else if (ExplosionClock.GetElapsedTime() > visningstid && ExplosionClock.GetElapsedTime() < (visningstid * 2)) { bildbredd = 128; //Gå till bild 2 } else if (ExplosionClock.GetElapsedTime() > (visningstid * 2) && ExplosionClock.GetElapsedTime() < (visningstid * 3)) { bildbredd = 192; //Gå till bild 3 } else if (ExplosionClock.GetElapsedTime() > (visningstid * 3) && ExplosionClock.GetElapsedTime() < (visningstid * 4)) { bildbredd = 256; //Gå till nästa bild } else if (ExplosionClock.GetElapsedTime() > (visningstid * 4) && ExplosionClock.GetElapsedTime() <= (visningstid * 5)) { bildbredd = 320; //Gå till nästa bild } Klassinstans.Sprite.SetSubRect(sf::IntRect(bildbredd-64,bildhojd-64,bildbredd,bildhojd)); //Visa bilden App.Draw(Klassinstans.Sprite);//Rita ut explosionen App.Display(); //visa upp ändringarna för användaren } //slut i x-led ExplosionClock.Reset(); // sätter om klockan till noll bildhojd = bildhojd + 64;//Hoppa ner en rad rutorY = rutorY + 1; //Öka till nästa rad } //while i y-led }//pang slutar
Färdig kod
redigeraObservera att i det här enkla exemplet kan du bara stänga fönstret med ESC-tangenten och inte genom att trycka på [x] på fönsterlisten.
Det finns en bugg i koden men den är medveten för att förenkla koden så att den blir lättare för nybörjare att förstå. I C++ räknar man alltid från 0, dvs. första bildrutan som skall visas har egentligen koordinaterna 0,0,63,63. Vanligtvis fungerar animationerna ändå trots att man börjar med 1 istället för 0 och bildrutorna blir 1 pixel för stora, men om du upptäcker "rester" från andra bilder i animationen eller märkliga streck, beror det antagligen på den här buggen. Då är det bara att räkna om hela animationen med basen 0 istället för basen 1 som används här.
#include <iostream> #include <SFML/System.hpp> #include <SFML/Window.hpp> #include <SFML/Graphics.hpp> #define SFML_STATIC //Se till så att det inte behövs extra DLL-filer using namespace std; // utifall att konsollen behövs för felsökning class Explosion { public : sf::Sprite Sprite; // en per instans }; void pang(float x, float y, Explosion &Klassinstans, sf::Image bildfilsnamn, sf::RenderWindow &App ); //Funktionen som initierar explosionen int main (int argc, char *argv) { //main startar //ladda in bild för explosionen sf::Image explosionsbildmap; //explosionens spritemap är 5 x 5 rutor 64x64 pixels stora if (!explosionsbildmap.LoadFromFile("xplosion17.png")) { cout << "Kan inte hitta bilden: xplosion17.png " << endl; } //Skapa en kopia av klassen explosionen Explosion Explosionskopia; sf::RenderWindow App(sf::VideoMode(800, 600, 32), "Test av explosion"); // Skapa fönstret vi skall testa explosionen i while (App.IsOpened()) { //while 1 startar sf::Event Event; //kolla om mus/tangentbord används while (App.GetEvent(Event)) { //while 2 börjar if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape)) App.Close();//avsluta programmet if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Return)) //Visa upp explosionen om man trycker ner return-knappen pang(100, 100, Explosionskopia, explosionsbildmap, App); //Slutligen visar vi upp ändringarna om och om igen många gånger i sekunden App.Clear(sf::Color(0, 100, 0)); //rensa allt i fönstret och ersätt med grönfärg App.Display(); //visa upp ändringarna för användaren } //while 2 slutar } //while 1 slutar } //main slutar void pang(float x, float y, Explosion &Klassinstans, sf::Image bildfilsnamn, sf::RenderWindow &App ) { int rutorY = 0; //max 5, bildrutor i y-led // int rutorX = 0; //max 5, bildrutor i x led //Obs, eftersom vi baserar animationen på tid och inte på vilken ruta man står på //behöver vi bara bekymra oss om vilken rad av rutor vi står på. int bildbredd = 64; //varje enskild rutas bredd int bildhojd = 64; //varje enskild rutas höjd sf::Clock ExplosionClock; //Skapa en timer för explosionen float visningstid = 0.01f; //0.01 sekund mellan varje Klassinstans.Sprite.SetPosition(x,y); //Placera ut animationen på rätt plats på spelplanen Klassinstans.Sprite.SetImage(bildfilsnamn); //ge animationen bilden av explosionen ExplosionClock.Reset(); //Se till så att klockan verkligen är 0 while ( rutorY < 5) //Så länge man är på någon rad {//while i y-led while (ExplosionClock.GetElapsedTime() < (visningstid * 5)) //Så länge man är på någon bild i en rad { //while i x-led //Välj ut vilken av de 5 bilderna vi skall ta //Genom att flyttain 64 eller 128 eller 192 osv. //Pixlar in på bildkartan if (ExplosionClock.GetElapsedTime() >= 0.0 && ExplosionClock.GetElapsedTime() < visningstid) { bildbredd = 64; //Gå till första bilden } else if (ExplosionClock.GetElapsedTime() > visningstid && ExplosionClock.GetElapsedTime() < (visningstid * 2)) { bildbredd = 128; //Gå till bild 2 } else if (ExplosionClock.GetElapsedTime() > (visningstid * 2) && ExplosionClock.GetElapsedTime() < (visningstid * 3)) { bildbredd = 192; //Gå till bild 3 } else if (ExplosionClock.GetElapsedTime() > (visningstid * 3) && ExplosionClock.GetElapsedTime() < (visningstid * 4)) { bildbredd = 256; //Gå till nästa bild } else if (ExplosionClock.GetElapsedTime() > (visningstid * 4) && ExplosionClock.GetElapsedTime() <= (visningstid * 5)) { bildbredd = 320; //Gå till nästa bild } Klassinstans.Sprite.SetSubRect(sf::IntRect(bildbredd-64,bildhojd-64,bildbredd,bildhojd)); //Visa bilden App.Draw(Klassinstans.Sprite);//Rita ut explosionen App.Display(); //visa upp ändringarna för användaren } //slut i x-led ExplosionClock.Reset(); // sätter om klockan till noll bildhojd = bildhojd + 64;//Hoppa ner en rad rutorY = rutorY + 1; //Öka till nästa rad } //while i y-led }//pang slutar
Explosion med ljud
redigeraEn explosion är ju inte en riktig explosion om det inte finns ett ljud i bakgrunden, men det ställer till vissa problem eftersom spelet inte riktigt vet när/hur ljudet skall spelas upp i samband med att animationen visas. Det allra enklaste är att helt enkelt starta ljudet i programkoden och sedan anropa explosionsanimationen. Det fungerar alltid men ger svårläst kod. En mer avancerad lösning är att lägga in ljudet i funktionen, men då måste funtionsdeklarationen byggas ut så att den också tar med ett ljud.
Tänk på att SFML i princip bara klarar ljud av "wav" och "ogg" format. Det bästa är om ljuden också är freeware. Roligast är så klart om du skapat dina ljud själv. Här är en hemsida på Internet med olika ljudeffekter för explosioner:
http://www.mediacollege.com/downloads/sound-effects/explosion/
Till exemplet används ljudfilen "bomb3" som verkar ha rätt ljud men litet för lång längd för vår explosionsanimation.
Lägga till ljudet i kod
redigeraFörst av allt måste vi se till så att det finns en include koppling för sfml:s ljudbibliotek i början av filen:
#include <SFML\Audio.hpp>
Precis som vi lägger in en bildfil i en imagehållare lägger vi till en ljudfil i en ljudhållare. Det är viktigt att vi laddar in filen i samband med att man startar programmet. Då ligger filen i minnet och anropas när den behövs. Något som går mycket snabbare än om man skall ladda in filen till programmet varje gång en explosion skall ske på spelplanen. Koden för att skapa en ljudbuffer är:
sf::SoundBuffer explosionsljud; //skapa en ljudbuffer/hållare if (!explosionsljud.LoadFromFile("bomb-03.wav")) //ladda in en fil i hållaren { cout << "Kan inte hitta ljudfilen: bomb-03.wav " << endl; }
Sedan får vi skriva om funktionen pang till:
void pang(float x, float y, Explosion &Klassinstans, sf::Image bildfilsnamn, sf::SoundBuffer explosionsfilnamn, sf::RenderWindow &App);
När vi anropar explosionen i programkoden får vi skriva:
//Visa upp explosionen om man trycker ner return-knappen pang(100, 100, Explosionskopia, explosionsbildmap, explosionsljud, App);
Inne i funktionen får du också lov att lägga in kod för att spela upp ljudet.
//Ladda in ljudet sf::Sound ljudeffekt; //skapa ett ljud i spelet som vi döper till ljudeffekt ljudeffekt.SetBuffer(explosionsfilnamn); // Ladda in ljudfilens värden i ljudet så att det går att spela upp. ljudeffekt.Play(); //spela upp ljudet
Det är synnerligen viktigt att du börjar spela upp ljudet innan animationssekvensen börjar. Skriver du istället in koden för att spela upp ljudet inne i animationen kommer det att bara spela lika länge som tiden mellan bildväxlingaran, och börja om uppspelningen varje gång en ny ruta visas upp. Det ger ett konstigt, smattrande oljud men inte ett ljud man kan identifiera.
Fel tid
redigeraNär du nu spelar upp explosionen kommer du att se explosionen, men bara höra en kort, kort bit av ljudet. Det beror på att ljudet avbryts när animationssekvensen är klar. Av någon anledning tycker SFML att bilden är viktigare än ljudet. Det hade så klart varit bättre om ljudet fortsatta att låta efter att bildsekvenen är klar, men för att uppnå det måste du börja programmera i threads/trådar och det är litet avancerat. Det du kan göra för att få kombinationen av animation och ljud att fungera är:
- endera förkortar du explosionsljudet
- eller så förlänger du explosionssekvensens tid.
Om du förlänger tiden mellan bildväxlingarna i animationen från 0.01 till 0.05 kommer explosionsanimationen att ta ca. 1.25 sekunder och det blir en relativt snygg explosion. Om du vill veta hur långt du kommit i uppspelningen av en ljudfil finns kommandot:
cout << "längd i ljudfil=" << ljudeffekt.GetPlayingOffset() << endl;
Då står det i konsollfönstret hur långt du kommit och det går att finjustera explosionerna så att animationens längd stämmer överns med ljudets längd, på ett ungefär. Med 0.05 sekunder mellan bildrutorna kommer explosionen att ske mycket långsammare, men det gör inte lika mycket om man har ett bra bakgrundsljud jämfört med om det är helt tyst.
Koden för funktionen
redigeraDen färdiga funktionen för pang blir således:
void pang(float x, float y, Explosion &Klassinstans, sf::Image bildfilsnamn, sf::SoundBuffer explosionsfilnamn, sf::RenderWindow &App) { //Ladda in ljudet sf::Sound ljudeffekt; //skapa ett ljud i spelet som vi döper till ljudeffekt ljudeffekt.SetBuffer(explosionsfilnamn); // Ladda in ljudfilens värden i ljudet så att det går att spela upp. ljudeffekt.Play(); //spela upp ljudet int rutorY = 0; //max 5, bildrutor i y-led // int rutorX = 0; //max 5, bildrutor i x led //Obs, eftersom vi baserar animationen på tid och inte på vilken ruta man står på //behöver vi bara bekymra oss om vilken rad av rutor vi står på. int bildbredd = 64; //varje enskild rutas bredd int bildhojd = 64; //varje enskild rutas höjd sf::Clock ExplosionClock; //Skapa en timer för explosionen float visningstid = 0.05; //0.05 sekund mellan varje bild Klassinstans.Sprite.SetPosition(x,y); //Placera ut animationen på rätt plats på spelplanen Klassinstans.Sprite.SetImage(bildfilsnamn); //ge animationen bilden av explosionen ExplosionClock.Reset(); //Se till så att klockan verkligen är 0 while ( rutorY < 5) //Så länge man är på någon rad {//while i y-led while (ExplosionClock.GetElapsedTime() < (visningstid * 5)) //Så länge man är på någon bild i en rad { //while i x-led //Välj ut vilken av de 5 bilderna vi skall ta //Genom att flytta in 64 eller 128 eller 192 osv. //Pixlar in på bildkartan if (ExplosionClock.GetElapsedTime() >= 0.0 && ExplosionClock.GetElapsedTime() < visningstid) { bildbredd = 64; //Gå till första bilden } else if (ExplosionClock.GetElapsedTime() > visningstid && ExplosionClock.GetElapsedTime() < (visningstid * 2)) { bildbredd = 128; //Gå till bild 2 } else if (ExplosionClock.GetElapsedTime() > (visningstid * 2) && ExplosionClock.GetElapsedTime() < (visningstid * 3)) { bildbredd = 192; //Gå till bild 3 } else if (ExplosionClock.GetElapsedTime() > (visningstid * 3) && ExplosionClock.GetElapsedTime() < (visningstid * 4)) { bildbredd = 256; //Gå till nästa bild } else if (ExplosionClock.GetElapsedTime() > (visningstid * 4) && ExplosionClock.GetElapsedTime() <= (visningstid * 5)) { bildbredd = 320; //Gå till nästa bild } Klassinstans.Sprite.SetSubRect(sf::IntRect(bildbredd-64,bildhojd-64,bildbredd,bildhojd)); //Visa bilden App.Draw(Klassinstans.Sprite);//Rita ut explosionen App.Display(); //visa upp ändringarna för användaren //cout << "längd i ljudfil=" << ljudeffekt.GetPlayingOffset() << endl; //Kolla hur långt in i ljudfilen du är } //slut i x-led ExplosionClock.Reset(); // sätter om klockan till noll bildhojd = bildhojd + 64;//Hoppa ner en rad rutorY = rutorY + 1; //Öka till nästa rad } //while i y-led }//pang slutar
Komplett kod
redigera#include <iostream> #include <SFML/System.hpp> #include <SFML/Window.hpp> #include <SFML/Graphics.hpp> #include <SFML/Audio.hpp> #define SFML_STATIC //Se till så att det inte behövs extra DLL-filer using namespace std; // utifall att konsollen behövs för felsökning class Explosion { public : sf::Sprite Sprite; // en per instans }; void pang(float x, float y, Explosion &Klassinstans, sf::Image bildfilsnamn, sf::SoundBuffer explosionsfilnamn,sf::RenderWindow &App); //Funktionen som initierar explosionen int main (int argc, char *argv) { //main startar //ladda in bild för explosionen sf::Image explosionsbildmap; //explosionens spritemap är 5 x 5 rutor 64x64 pixels stora if (!explosionsbildmap.LoadFromFile("xplosion17.png")) { cout << "Kan inte hitta bilden: xplosion17.png " << endl; } sf::SoundBuffer explosionsljud; //skapa en ljudbuffer/hållare if (!explosionsljud.LoadFromFile("bomb-03.wav")) //ladda in en fil i hållaren { cout << "Kan inte hitta ljudfilen: bomb-03.wav " << endl; } //Skapa en kopia av klassen explosionen Explosion Explosionskopia; sf::RenderWindow App(sf::VideoMode(800, 600, 32), "Test av explosion"); // Skapa fönstret vi skall testa explosionen i while (App.IsOpened()) { //while 1 startar sf::Event Event; //kolla om mus/tangentbord används while (App.GetEvent(Event)) { //while 2 börjar if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape)) App.Close();//avsluta programmet if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Return)) //Visa upp explosionen om man trycker ner return-knappen pang(100, 100, Explosionskopia, explosionsbildmap, explosionsljud, App); //Slutligen visar vi upp ändringarna om och om igen många gånger i sekunden App.Clear(sf::Color(0, 100, 0)); //rensa allt i fönstret och ersätt med grönfärg App.Display(); //visa upp ändringarna för användaren } //while 2 slutar } //while 1 slutar } //main slutar void pang(float x, float y, Explosion &Klassinstans, sf::Image bildfilsnamn, sf::SoundBuffer explosionsfilnamn, sf::RenderWindow &App) { //Ladda in ljudet sf::Sound ljudeffekt; //skapa ett ljud i spelet som vi döper till ljudeffekt ljudeffekt.SetBuffer(explosionsfilnamn); // Ladda in ljudfilens värden i ljudet så att det går att spela upp. ljudeffekt.Play(); //spela upp ljudet int rutorY = 0; //max 5, bildrutor i y-led // int rutorX = 0; //max 5, bildrutor i x led //Obs, eftersom vi baserar animationen på tid och inte på vilken ruta man står på //behöver vi bara bekymra oss om vilken rad av rutor vi står på. int bildbredd = 64; //varje enskild rutas bredd int bildhojd = 64; //varje enskild rutas höjd sf::Clock ExplosionClock; //Skapa en timer för explosionen float visningstid = 0.1; //0.05 sekund mellan varje bild Klassinstans.Sprite.SetPosition(x,y); //Placera ut animationen på rätt plats på spelplanen Klassinstans.Sprite.SetImage(bildfilsnamn); //ge animationen bilden av explosionen ExplosionClock.Reset(); //Se till så att klockan verkligen är 0 while ( rutorY < 5) //Så länge man är på någon rad {//while i y-led while (ExplosionClock.GetElapsedTime() < (visningstid * 5)) //Så länge man är på någon bild i en rad { //while i x-led //Välj ut vilken av de 5 bilderna vi skall ta //Genom att flytta in 64 eller 128 eller 192 osv. //Pixlar in på bildkartan if (ExplosionClock.GetElapsedTime() >= 0.0 && ExplosionClock.GetElapsedTime() < visningstid) { bildbredd = 64; //Gå till första bilden } else if (ExplosionClock.GetElapsedTime() > visningstid && ExplosionClock.GetElapsedTime() < (visningstid * 2)) { bildbredd = 128; //Gå till bild 2 } else if (ExplosionClock.GetElapsedTime() > (visningstid * 2) && ExplosionClock.GetElapsedTime() < (visningstid * 3)) { bildbredd = 192; //Gå till bild 3 } else if (ExplosionClock.GetElapsedTime() > (visningstid * 3) && ExplosionClock.GetElapsedTime() < (visningstid * 4)) { bildbredd = 256; //Gå till nästa bild } else if (ExplosionClock.GetElapsedTime() > (visningstid * 4) && ExplosionClock.GetElapsedTime() <= (visningstid * 5)) { bildbredd = 320; //Gå till nästa bild } Klassinstans.Sprite.SetSubRect(sf::IntRect(bildbredd-64,bildhojd-64,bildbredd,bildhojd)); //Visa bilden //App.Clear(sf::Color(0, 100, 0)); //rensa allt i fönstret och ersätt med grönfärg App.Draw(Klassinstans.Sprite);//Rita ut explosionen App.Display(); //visa upp ändringarna för användaren //cout << "längd i ljudfil=" << ljudeffekt.GetPlayingOffset() << endl; //Kolla hur långt in i ljudfilen du är } //slut i x-led ExplosionClock.Reset(); // sätter om klockan till noll bildhojd = bildhojd + 64;//Hoppa ner en rad rutorY = rutorY + 1; //Öka till nästa rad } //while i y-led }//pang slutar
Är det så att animationsbilderna läggs på varandra får du lägga in raden:
App.Clear(sf::Color(0, 100, 0)); //rensa allt i fönstret och ersätt med grönfärg
före draw. Se själv i koden, jag har kommenterat ut den raden i den färdiga koden på slutet. Det är bara att ta bort // tecknen innan.