SFML community forums
Help => Graphics => Topic started by: ingwik on November 13, 2011, 01:21:57 pm
-
I'm using VC++ 2010 express, Win 7 64 enterprise and SFML 1.6
I'm trying to make a simple function to show an explosion. In the end, it's supposed to be part of an explosion class. Righht now, it should fire once when the enter key is pressed, but it doesn't.
I have two errors in the code that I don't understand:
1: The function fires twice. It shouldn't but I can't find any solutuion to the problem.
2: Copyrect fail, I see the whole bitmap-map and not copyrect squares creating an animation sequence.
The picture is:
http://cdn.pimpmyspace.org/media/pms/c/b9/9e/ez/xplosion17.png
Code:
#include <iostream>
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#define SFML_STATIC //No extra DLL
using namespace std; // to show the console
class Explosion
{
public :
sf::Sprite Sprite; //The explosion sprite
};
void pang(float x, float y, Explosion &Klassinstans, sf::Image bildfilsnamn, sf::RenderWindow &App );
//Function to show explosion, forward declaration
int main (int argc, char *argv)
{ //main start
//load pic
sf::Image explosionsbildmap;
//Size of spritemap 5 x 5 squares 64x64 pixels big
if (!explosionsbildmap.LoadFromFile("xplosion17.png"))
{
cout << "Can't find: xplosion17.png " << endl;
}
//Create a copy of the class
Explosion Explosionskopia;
sf::RenderWindow App(sf::VideoMode(800, 600, 32), "Test av explosion");
// Creating render window
while (App.IsOpened())
{ //while 1 start
sf::Event Event; //Check if event is used
while (App.GetEvent(Event))
{ //while 2 start
if (Event.Type == sf::Event::Closed)
App.Close();//shut down program
if (App.GetInput().IsKeyDown(sf::Key::Return))
//Show the explosion
pang(100, 100, Explosionskopia, explosionsbildmap, App);
App.Clear(sf::Color(0, 100, 0)); //Green background
App.Display(); //Show changes
} //while 1 ends
} //while 2 ends
} //main ends***************************************
//Function description
void pang(float x, float y, Explosion &Klassinstans, sf::Image bildfilsnamn, sf::RenderWindow &App )
{
int rutorY = 0; //max 5, pictures y
int rutorX = 0; //max 5, pictures x
int bildbredd = 64; //width of frame
int bildhojd = 64; //height of frame
sf::Clock ExplosionClock;
//Create a timer for the explosion
float visningstid = 0.1; // 0.1 sec between each frame
Klassinstans.Sprite.SetPosition(x,y);
//Place the explosion on the game board
Klassinstans.Sprite.SetImage(bildfilsnamn);
ExplosionClock.Reset(); //make sure the clock i 0
while ( rutorY < 5)
{
while (rutorX < 5)
{
if ((ExplosionClock.GetElapsedTime() > visningstid - 0.0) && (ExplosionClock.GetElapsedTime() < visningstid))
Klassinstans.Sprite.SetSubRect(sf::IntRect(bildbredd-64,bildhojd-64,bildbredd,bildhojd)); //Show first frame
//Check what happens in console
cout << "koordinater"<< bildbredd-64 << " , " << bildhojd-64 << " , " << bildbredd << " , " << bildhojd << " , " << endl;
cout << "tidskod " << visningstid << endl;
App.Draw(Klassinstans.Sprite);//Change picture
App.Display(); //Show changed picture
bildbredd = bildbredd + 64;
visningstid = visningstid + visningstid;
rutorX = rutorX + 1;
}
rutorX = 0;//Begin at first pic in next row
bildhojd = bildhojd + 64;
bildbredd = 64;
rutorY = rutorY + 1; //Switch to next row
//Show result in console
cout << "Y=" << rutorY << endl;
}
}//pang ends
-
I solved it eventually, much thanks to this post:
http://www.sfml-dev.org/forum/viewtopic.php?t=5378&highlight=clock
In the "While app is opened" I need:
while (App.IsOpened())
{ //while 1 start
const sf::Input &Input = App.GetInput();
bool returnKeyDown = Input.IsKeyDown(sf::Key::Return);
And then, instead of:
if (App.GetInput().IsKeyDown(sf::Key::Return))
I use
if (returnKeyDown == true)
This simple change make the routine run once instead of twice. Why? I can't say really. I suppose the first (faulty) routine reacts two times or maybe more since the key is pressed down, while the other (correct) routine just checks if the key is down and dont fire every cycle.
The function had one row of code too much. Unfortunately it's the row of code that adjust the time. By comment out:
//if ((ExplosionClock.GetElapsedTime() > visningstid - 0.0) && (ExplosionClock.GetElapsedTime() < visningstid))
the explosion show all copy rects in a serie instead of the whole spritesheet at once, Anyway, it's solved and work now, even though it explodes so fast that I nearly can't see what happens. Any suggestion about how to change that?
-
This is not a solution, and I'm surprised that it works. If you want to catch the single "return pressed" event, then use the... KeyPressed event. Not something that returns true as long as the key is down.
-
Your solution worked too Laurent. I realized I was counting the frames in the explosion bitmap, instead of counting time. To get the correct animation sequence, I had to do like this:
#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 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 1 slutar
} //while 2 slutar
} //main slutar
void pang(float x, float y, Explosion &Klassinstans, sf::Image bildfilsnamn, sf::RenderWindow &App )
{
bool avsluta=false;
int rutorY = 0; //max 5, bildrutor i y-led
int rutorX = 0; //max 5, bildrutor i x led
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;
Klassinstans.Sprite.SetPosition(x,y);
//Placera ut den på rätt plats på spelplanen
Klassinstans.Sprite.SetImage(bildfilsnamn);
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
if (ExplosionClock.GetElapsedTime() < visningstid && ExplosionClock.GetElapsedTime() > 0.0)
{
bildbredd = 64; //Gå till första bilden
}
else if (ExplosionClock.GetElapsedTime() < (visningstid * 2) && ExplosionClock.GetElapsedTime() > visningstid)
{
bildbredd = 128; //Gå till bild 2
}
else if (ExplosionClock.GetElapsedTime() < (visningstid * 3) && ExplosionClock.GetElapsedTime() > (visningstid * 2))
{
bildbredd = 192; //Gå till bild 3
}
else if (ExplosionClock.GetElapsedTime() < (visningstid * 4) && ExplosionClock.GetElapsedTime() > (visningstid * 3))
{
bildbredd = 256; //Gå till nästa bild
}
else if (ExplosionClock.GetElapsedTime() < (visningstid * 5) && ExplosionClock.GetElapsedTime() > (visningstid * 4))
{
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