Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Animation show twice, why?  (Read 2305 times)

0 Members and 1 Guest are viewing this topic.

ingwik

  • Jr. Member
  • **
  • Posts: 65
    • View Profile
Animation show twice, why?
« 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:
Code: [Select]
#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

ingwik

  • Jr. Member
  • **
  • Posts: 65
    • View Profile
Animation show twice, why?
« Reply #1 on: November 13, 2011, 09:59:16 pm »
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:
 
Code: [Select]
while (App.IsOpened())
     { //while 1 start
   const sf::Input &Input = App.GetInput();
   bool returnKeyDown = Input.IsKeyDown(sf::Key::Return);


And then, instead of:
Code: [Select]
if (App.GetInput().IsKeyDown(sf::Key::Return))
I use
Code: [Select]
 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:
Code: [Select]
//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?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Animation show twice, why?
« Reply #2 on: November 13, 2011, 10:19:08 pm »
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.
Laurent Gomila - SFML developer

ingwik

  • Jr. Member
  • **
  • Posts: 65
    • View Profile
Animation show twice, why?
« Reply #3 on: November 18, 2011, 03:23:19 pm »
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:


Code: [Select]

#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