Programmera spel i C++ för nybörjare/Animation 1

Från Wikibooks


Baserat på VC++ 2010 express, Win 7 och SFML 1.6, du bör ha gjort installationerna för ett fungerande SFML-fönster i ditt projekt innan du börjar.

Att skapa animationer på ett enkelt sätt är tämligen omöjligt i SFML. I DirectX finns i alla fall en sprite-animationsklass som standard, tyvärr ingår inte den i SFML så man får dyka ner i arbeten som andra har gjort.

I SFML:s wiki http://www.sfml-dev.org/wiki/en/sources/anisprite finns en enkel lektion över hur man får en liten pojke att gå omkring. För att få exemplet att fungera måste du dessutom skapa ett två andra projekfiler:

AniSprite.h – där klassen anisprite deklareras.
AniSprite.cpp – där koden för anisprite finns.

Är det så att du vill kunna animera spelpjäser i framtiden, får du leva med att dessa filer alltid måste ingå i projekten i framtiden.

En animationsklass[redigera]

på det stora hela taget direkt från wikin, men kommentarer och liknande är översatt till svenska. Se till så att du har ett fungerande projekt där alla dll filer är länkade på rätt sätt. Spara ner filen med den gående pojken från http://www.sfml-dev.org/wiki/_media/en/sources/character.png Lägg den i den mapp som main.cpp ligger så att programmet hittar den. Sprite-kartan är 191x256 punkter och varje bild i den är 47 pixels bred och 64 pixels hög Byt ut koden i main.cpp (vanliga programmeringsfönstret) till:

#include <iostream>
#include <SFML\System.hpp>
#include <SFML\Graphics.hpp>
#include <SFML\Window.hpp>
#include <AniSprite.h>


 int main() 
    {  //Början av programkörningen

sf::RenderWindow App(sf::VideoMode(800, 600, 32), "Test - animation"); 
float pojkfart = 0.05f; //hastigheten när pojken flyttar sig
				
 // Ladda in in sprite-karta, en uppsättning bilder som skall visas i sekvens
 //Första bilden = 0, alla måste vara lika stora.
  sf::Image pojkkarta;
   if (!pojkkarta.LoadFromFile("character.png"))
	return EXIT_FAILURE;
  
  //Skapa hållaren för sprite-animationen
  AniSprite Spritepojk(pojkkarta,47,64); //bildkarta och storleken på varje enskild bild x,y-led
   Spritepojk.SetLoopSpeed(12); //12 fps
   //Spritepojk.Play(0,1); //Frivillig - visa första och andra bilden enbart vid programstart, får inte vara 0,0

  Spritepojk.SetPosition(200.f, 200.f); //Placera ut bilden

	   bool left, right, up, down; //sk. state enum- 
	   left = right = up = down = false; //avgör om animationen skall visas eller ej när pojken går.


while(App.IsOpened())
{
	sf::Event Event; 

	
while (App.GetEvent(Event)) // Ta hand om händelser 
   { //while 2

      if (Event.Type == sf::Event::Closed) //kryssat på [x] symbolen? stäng programmet
         App.Close(); 

      if (Event.Type == sf::Event::KeyPressed) // En tangent har tryckts ner

             { //if 1

               if (Event.Key.Code == sf::Key::Escape) // ESC tangenten = stäng programmet
                    App.Close(); 

              } //slut if 1

  } //slut, while 2

//OBS Man räknar inte rutorna från 0, utan från 1. Första rutraden i animationen
//består av fyra rutor, numrerade från 1 till 4, i motsats till att C++ vanligen börjar
//räkna från 0

if (App.GetInput().IsKeyDown(sf::Key::Left)) 
	 {
	 Spritepojk.Move(-pojkfart, 0); //Går åt vänster
		 if (left == false) //redo att starta animation
		 {
 	       Spritepojk.Play(13,16); //fyra sista bilderna
		   left = true; //ställ om så att det går-
		   down = right = up =false; //att visa animation med andra tangenter
		 }
   } //Visa nedersta raden, pojken går åt vänster

else if (App.GetInput().IsKeyDown(sf::Key::Right)) 
	 {
	 Spritepojk.Move(pojkfart, 0);
		 if (right == false)
		 {
	    Spritepojk.Play(5,8); 
		right = true;
		left = up = down = false;
		 }
    }//Visa andra raden, pojken går åt höger

else if (App.GetInput().IsKeyDown(sf::Key::Up)) 
	{
		Spritepojk.Move(0, -pojkfart); 
		if(up == false)
		{
		Spritepojk.Play(1,4); 
		up = true;
		left = right = down = false;
		}  
   }//Visa första raden, man ser ryggen på pojken

else if (App.GetInput().IsKeyDown(sf::Key::Down)) 
	{
	Spritepojk.Move(0, pojkfart);
	if (down == false)
	{
		Spritepojk.Play(9,12); 
		down = true;
		left = right = up = false;
   }
}//Visa tredje raden, man ser ansiktet på pojken
else
{
	Spritepojk.Stop(); //Ingen animation när han står still
	left=right=up=down=false; //så att man kan klicka 2 ggr i rad 
	                          //och få animation bägge gångerna
}


// Rensa skärmen
    App.Clear();	
//updatera animation
    Spritepojk.Update();	 	 
    App.Draw(Spritepojk);
    App.Display();
}

return 0;
} //slut på programkörningen
 	 

Nu får du mängder med felmeddelanden om du bygger projektet [CTRL]+[ALT]+[B], tre steg kvar innan det skall fungera.

Skapa projektfilerna[redigera]

  • Högerklicka i vänster panel på den feta texten som har projektets namn.
  • I mitten av menyn finns alternativet [Add], välj det.
  • Välj [New Item...], översta alternativet.
  • Mitt på sidan finns nu några filalternativ. Ett har ett ”h” mitt på. Klicka på den, och ge den namnet ”AniSprite.h” utan citattecken.
  • Klicka på [Add] knappen längst ner till höger.

Nu får du upp ett helt tomt dokument. Det skall dessutom synas under mappen [Header Files] i den vänstra panelen Kopiera in följande text i dokumentet:

// AniSprite.h
#pragma once //Läs bara in filen en enda gång även om den associeras flera gånger
#include <SFML\Graphics.hpp> //fellänkad i originaldokumentet

class AniSprite : public sf::Sprite
{
public:
	AniSprite();
		//Initieringslista

	AniSprite(const sf::Image& Img, int frameWidth, int frameHeight);
	~AniSprite(void);
	//Ange detta när du skapar en animation,
	//T.ex. Sprite(Image,47,64);

	//var i animationen skall man börja?
	sf::IntRect AniSprite::GetFramePosition(int frame);
		
	//Hur många bilder skall visas?
	int GetFrameCount();

	//Hur stora är bilderna?
	void SetFrameSize(int frameWidth, int frameHeight);
	
      //Ställer in visaren på nuvarande bild.
	void SetFrame(int frame);

	//sets loop-hastighetens bildvisning i bilder per sekund
	void SetLoopSpeed(float fps);

	//starta animationen/loopningen
	void Play();

	//Nummer på startbild och nummer på slutybild
	void Play(int start, int end);

	//stopp
	void Stop();

	//rita upp förändring
	void Update();
private:
	sf::Clock clock;
	float fps;
	bool isPlaying;
	int loopStart;
	int loopEnd;
	int currentFrame;	
	int frameWidth;
	int frameHeight;
};

Nu skall du skapa filen med klassens programkod: Högerklicka i på ditt projektnamn där det är skrivet med fet stil i den vänstra panelen igen.

I mitten av menyn finns alternativet [Add], välj det. Välj [New Item...], översta alternativet. Näst överst bland alternativen på den sida som kommer upp finns bilden av ett dokument med två gula + tecken på. Det heter C++ File (.cpp). Välj det och döp det till ”AniSprite.cpp ” utan citattecken. Klicka på [Add] knappen längst ner till höger. Nu får du upp ett helt tomt dokument. Det skall dessutom synas under mappen [Source Files] i den vänstra panelen Kopiera in följande text i dokumentet:

//AniSprite.cpp
#include "AniSprite.h"

AniSprite::AniSprite(void)
	: sf::Sprite() 
{
	this->fps=1;
	this->currentFrame=0;
	this->isPlaying = false;
	this->loopStart = 0;
	this->SetFrameSize(0, 0);
}

AniSprite::AniSprite(const sf::Image& Img, int frameW, int frameH)
		: sf::Sprite(Img)
{
	this->fps=1;
	this->currentFrame=0;
	this->isPlaying = false;
	this->loopStart = 0;
	this->SetFrameSize(frameW, frameH);
	//Dags att beräkna animationen
}

AniSprite::~AniSprite(void)
{
}
int AniSprite::GetFrameCount() //Avgör antalet frames isprite-sheet
{
	unsigned int across = 
		this->GetImage()->GetWidth() /
		this->frameWidth;
	unsigned int down = 
		this->GetImage()->GetHeight() /
		this->frameHeight;

	return across*down;
}
//första bilden är bild 0
sf::IntRect AniSprite::GetFramePosition(int frame)
{
	//get number across and down
	unsigned int across = 
		(this->GetImage()->GetWidth() /
		this->frameWidth);
	unsigned int down = 
		(this->GetImage()->GetHeight() /
		this->frameHeight);	

   int tileY = frame / across ; //hitta Y på sprite sheet
   int tileX = frame % across ; //hitta X på sprite sheet

	sf::IntRect result(
		tileX*this->frameWidth,
		tileY*this->frameHeight,
		tileX*this->frameWidth + this->frameWidth,
		tileY*this->frameHeight + this->frameHeight);
// for SFML 2.0 använd dessa och kommentera bort ovanstående
/*	sf::IntRect result(
		tileX*this->frameWidth,
		tileY*this->frameHeight,
		this->frameWidth,
		this->frameHeight);
*/

	//end
	return result;	

}
//
void 
AniSprite::SetFrameSize(int frameW, int frameH)
{
	this->frameWidth = frameW;
	this->frameHeight = frameH;
	this->SetSubRect(sf::IntRect(0,0,frameW,frameH));
}
//Ställer in nuvarande bild
void 
AniSprite::SetFrame(int frame)
{
	this->currentFrame = frame;
}
//ställer in animationshastigheten i bilder per sekund
void 
AniSprite::SetLoopSpeed(float newfps)
{
	this->fps = newfps;
}
//startar animationen
void 
AniSprite::Play()
{
	this->Play(0,GetFrameCount());
}
void 
AniSprite::Play(int start, int end)
{	
	loopStart = start;
	loopEnd = end;
	currentFrame = start;
	isPlaying = true;	
	clock.Reset();
}
//stoppar animationen
void
AniSprite::Stop()
{
	isPlaying = false;
}
//uppdaterar funktionen
void
AniSprite::Update()
{
	if(isPlaying)
	{
		int frameCount = loopEnd - loopStart;
               // för sfml 2.0 byt ovanstående rad med...
//		int frameCount = (loopEnd+1) - loopStart;
 
		float timePosition = (clock.GetElapsedTime() * fps);
		currentFrame = loopStart + 
			(int)timePosition % frameCount;
		//printf("%f:%i\n",clock.GetElapsedTime(),currentFrame);

		this->SetSubRect(GetFramePosition(currentFrame));		
	}
}

Du kan fortfarande inte pröva projektet. Det sista du måste göra är att spara AniSprite.h på något ställe som Visual C++ 2010 express hittar till. Titta först i ditt projekt där du sparat bilderna, så kommer du att se att både AniSprite.cpp och AniSprite.h ligger i rätt mapp. Tyvärr är C++ för korkat för att förstå det. Kopiera bägge filerna och klistra in dem i SFML:s include bibliotek. Du hittar var det är genom att.

  • Högerklicka på ditt projektnamn i vänstra panelen.
  • Välj [properties] alternativet längst ner i menyn som poppar upp.
  • Ändra alternativrutan överst till vänster till [All Configurations]
  • Klicka på C/C++ alternativet.
  • Välj [General]
  • På översta raden står det var include biblioteket finns. För mig ligger det på:
C:\sfml16\SFML-1.6\include
  • Klistra in filerna där. Först nu går det att köra animationen.

Provkör, nu borde det gå att vandra omkring med pojken.

Andra programmet[redigera]

Om det är så att du skapar ett nytt spel och vill använda AniSprite.h och AniSprite.cpp i det projektet får du söka upp den mapp där du sparat filerna. Starta VC++, öppna ditt projekt och högerklicka på ditt projektnamn (svart text högt upp). Välj add/lägg till och sedan Existing Item. Därefter söker du upp AniSprite.h och AniSprite.cpp och länkar in dem i ditt spelprojekt den vägen.