Jump to content
  • Advertisement
Sign in to follow this  
walle

I have a problem with my sprite engine

This topic is 4870 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello. Before I start: I use SDL with c++ and I use DevC++ on windows professional sp1 Ok, this will be kind of long, so if someone reads trough it I'll be happy =) But what about getting to the point? I've made a little sprite engine to use in my games. But it doesn't work at all, or maybe it does, just that I've made a programming error. Anyway I get this error: (window caption) Microsoft Visual C++ Runtime Library (the error message) Runtime error! Program: "the path to my program" This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information. I assume that the error is in the drawing code, because it doesn't happen if I only load in the sprite. But if I check the width of a sprite, which is set when the sprite is loaded it just returns 0. so there have to be some error in the loading code too. Ok, before I post the source I just want to explain some stuff. I'm going to make a special sprite file format, just a zip file that holds all animations and so, but for now I use folders because it'll be easy to change when I'm ready. But the file format looks like this: Sprite // The main folder ->animations.info // A file describing how many animations the sprite has animationfolder // One of all animation folders ->frames.info // A file describing how many frames the animation has frame#1.png // One of all frames in the animation This is because I'll make a tool for making sprites, so the artist (if I work with someone) can make the sprites more easily Ok, I'm sorry for the messy source, I haven't really learned to make "good" source... The header file sprite.h
#ifndef SPRITE_H 
#define SPRITE_H 
#include <string> 
#include <vector> 
#include <fstream> 
#include <SDL/SDL.h> 
#include <SDL/SDL_Image.h> 
// A single frame in the animation 
struct frame 
{ 
    int delay; // The number of milliseconds to wait before next frame 
    SDL_Surface *img; // The image of the frame 
}; 

// A whole animation 
struct animation 
{ 
    std::string name; // The name of the animation, the name of the folder the frames are in 
    int framenr; // Keeping track of which frame we are currently viewing 
    std::vector<frame> frames; // All frames 
    
}; // A basic animated sprite 
class sprite 
{ 
    public: 
        sprite(); 
        ~sprite(); 
        
        // Self explained just look at the names 
        int getx(); 
        int gety(); 
        int getw(); 
        int geth(); 
        SDL_Rect getrect(); 
        std::string getanimation(); 
        
        void setx(int x); 
        void sety(int y); 
        void setw(int w); 
        void seth(int h); 
        void setrect(SDL_Rect rect); 
        void setanimation(std::string name); 
        
        // This function loads a sprite from a directory, first it checks how many different animations 
        // the sprite has, then loads the frames of every animation. The width and height of the sprite 
        // is decided by the first frame of the first animation 
        bool load(std::string dir, SDL_Surface *dest); 
        
        // This function draws the sprite, it animates automatically, if it isn't paused 
        void draw(); 
        
        // Animation controls 
        void pause(); 
        void resume(); 
        void reset(); 
        
    private: 
        SDL_Rect m_rect; // The rect of the sprite x,y,width and height values 
        int m_animation; // Keeps track of which animation we are on 
        int m_lastframe; // Keeps track of how many milliseconds it has been since the last frame 
        std::vector<animation> m_animations; // Every animation 
        SDL_Surface *m_dest; // The surface to draw to 
        bool m_paused; // Is the animation paused? 
}; 

// Load a image and convert it to the format SDL use 
SDL_Surface* load_IMG(std::string file); 

#endif

The cpp file sprite.cpp
#include "sprite.h" 
// The constructor clears all vectors 
sprite::sprite() 
{ for(int i=0; i<m_animations.size(); i++)
    {
        m_animations.at(i).frames.clear();
    }    
    m_animations.clear();
}

// The destructor doesn't do anythin becuase we don't have any allocated memory (by new)
sprite::~sprite() {}

// These are self explaned
int sprite::getx()
{
    return m_rect.x;
}    

int sprite::gety()
{
    return m_rect.y;
}

int sprite::getw()
{
    return m_rect.w;
}

int sprite::geth()
{
    return m_rect.h;
}

SDL_Rect sprite::getrect()
{
    return m_rect;
}

std::string sprite::getanimation()
{
    return m_animations.at(m_animation).name;
}

void sprite::setx(int x)
{
    m_rect.x=x;
}     

void sprite::sety(int y)
{
    m_rect.y=y;
}

void sprite::setw(int w)
{
    m_rect.w=w;
}

void sprite::seth(int h)
{
    m_rect.h=h;
}   

void sprite::setrect(SDL_Rect rect)
{
    m_rect=rect;
}

// Change the animation if there are a animation with the name 
void sprite::setanimation(std::string name)
{
    for(int i=0; i<m_animations.size(); i++) 
    { 
        if(name==m_animations.at(i).name) { m_animation=i; } 
    } 
} 

// This function loads a sprite from a directory, first it checks how many different animations 
// the sprite has, then loads the frames of every animation. The width and height of the sprite 
// is decided by the first of the first animation 
bool sprite::load(std::string dir, SDL_Surface *dest) 
{ 
    // Temporary variables to receive the file input 
    std::string temps; 
    int tempi; 
    // Make a string by adding the dir and a specified file 
    std::string file=dir+"/animations.info"; 
    std::ifstream fin; // Our fstream object, read only 
    fin.open(file.c_str()); // Open the file 
    if(fin==NULL) { return false; } // Return if the file don't exist or some other error 
    else 
    { 
        // Read by the "Animations:" string in the beginning of the file then read in how many animations there are to tempi 
        fin>>temps>>tempi; 
        m_animations.resize(tempi); // Resize the vector to the number of animations there are 
        for(int i=0; i<m_animations.size(); i++)
        {
            getline(fin,temps);    // Read the folder name for the animation
            m_animations.at(i).name=temps;   // Assign the folder name to the animations name
        }
    }    
    fin.close();   // We are done with this file
    
    // In this loop we'll load the frames of every animation
    for(int i=0; i<m_animations.size(); i++) 
    { 
        // Make a filename of the dir and the name of the animation and the file containing the frames data 
        // Example: dir="gfx/sprites/hero" animation name="walkleft" then the whole path becomes: 
        // "gfx/sprites/hero/walkleft/frames.info" 
        file=dir+"/"+m_animations.at(i).name+"/frames.info"; 
        fin.open(file.c_str()); // Open the file 
        if(fin==NULL) { return false; } // Exit if something unexpected happens 
        else 
        { 
            fin>>temps>>tempi; // Read past the "Frames:" string in the file and read the number of frames this animation has 
            m_animations.at(i).frames.resize(tempi); // Resize the vector to have place for all the frames 
            // This loop goes trough all the filenames and loads the frame image to it's surface 
            for(int k=0; k<m_animations.at(i).frames.size(); k++)
            {
                fin>>temps>>tempi; // Read the filename and the delay for the frame 
                std::string img; // Another temporary string to load the image 
                img=dir+"/"+m_animations.at(i).name+"/"+temps; // We do the same thing as above, make a whole path for the file 
                m_animations.at(i).frames.at(k).img=load_IMG(img); // Load the image and convert it to the format SDL uses 
                m_animations.at(i).frames.at(k).delay=tempi; // Set the delay for the frame 
            } 
            fin.close(); // We are done with the file 
        } 
        m_rect.x=0; // Set the x value to 0 
        m_rect.y=0; // Set the y value to 0 
        // Set the width and height of the sprite to the width and height of the first frame of the first animation 
        m_rect.w=m_animations.at(0).frames.at(0).img->w; 
        m_rect.h=m_animations.at(0).frames.at(0).img->h; 
        m_animation=0; // Use the first animation 
    } 
    return true; 
} 

// This function draws the sprite, it animates automatically, if it isn't paused 
void sprite::draw() 
{ 
    if(m_paused==false) // Check if the sprite animation is paused 
    { 
        // Check if the time we showed the last frame + the delay of this frame is greater or equal to SDL_GetTicks() 
        if(m_lastframe+m_animations.at(m_animation).frames.at(m_animations.at(m_animation).framenr).delay>=SDL_GetTicks()) 
        { 
            // If ot is change to the next frame 
            m_animations.at(m_animation).framenr++; 
            // If it is the last frame of the animation we'll loop it, setting the framenr to the the first frame 
            if(m_animations.at(m_animation).framenr==m_animations.at(m_animation).frames.size()) 
            { 
                m_animations.at(m_animation).framenr=0; 
            } 
            m_lastframe=SDL_GetTicks(); // We showed this frame now, save the time 
        } 
    } 
    
    // Blit the frame to the surface we assigned the sprite to 
    SDL_BlitSurface(m_animations.at(m_animation).frames.at(m_animations.at(m_animation).framenr).img, NULL, m_dest, &m_rect); 
} 
// Animation controls 
void sprite::pause() 
{ 
    m_paused=true; 
} 

void sprite::resume() 
{ 
    m_paused=false; 
} 

void sprite::reset() 
{ 
    m_animations.at(m_animation).framenr=0; 
} 

// Load a image and convert it to the format SDL use 
SDL_Surface* load_IMG(std::string file) 
{ SDL_Surface *temp1, *temp2; temp1 = IMG_Load(file.c_str()); 
temp2 = SDL_DisplayFormat(temp1); 
SDL_FreeSurface(temp1); 
return temp2; 
} 

Any help finding this error is appreciated //walle

Share this post


Link to post
Share on other sites
Advertisement
Yes...But I don't get any debug information, the error message just comes up directly. and when you press the error message the application shuts down.

//walle

Share this post


Link to post
Share on other sites
You're not checking the return values from any of the SDL*/IMG* functions. It is possible that one of them is failing.

Also, you might try sprinkling some debug output through your code to help narrow down where the error occurs.

Share this post


Link to post
Share on other sites
Well I don't do that in this code, but I've been trying to solve this my self, and the image isn't pointing to NULL.

I'll add some debug statements, but I don't really know where to do that...I'll just put them where it feels right.

//walle

Share this post


Link to post
Share on other sites
OK, been playing with this and have found the first problem. You are not clearing the ifstream before opening another file. Try this in sprite::load.


fin.close(); // Close this file
fin.clear(); // We are done with this file



As it stands everytime you recall fin.open it is reopening the same file (animations.info).

Unfortunately, this doesn't solve the problem with the error you are receiving. Still looking into it. The sprite::draw function is bugging out at the the following line though from what I can make out.


if(m_lastframe+m_animations.at(m_animation).frames.at(m_animations.at(m_animation).framenr).delay>=SDL_GetTicks())



The 'Microsoft Visual C++ Runtime Library' makes me think it is a problem with the SDL_Image library but not 100%.

Going to keep debuggin, this is a nice challenge for a newbie like myself. :)

Share this post


Link to post
Share on other sites
Quote:
Original post by JWindebank
OK, been playing with this and have found the first problem. You are not clearing the ifstream before opening another file. Try this in sprite::load.

*** Source Snippet Removed ***

As it stands everytime you recall fin.open it is reopening the same file (animations.info).



Thanks, didn't know that you have to clear the fstream handle (is it called that?) That explaines why the width of the sprite is 0...

Quote:
Original post by JWindebank
Going to keep debuggin, this is a nice challenge for a newbie like myself. :)


Well who isn't a noob :D


//walle


Share this post


Link to post
Share on other sites
Ok I've come closer to the problem I think. When I read from animations.info I don't jump down one row after I've read in the number of animations...

Fixed part of the source:

// Read by the "Animations:" string in the beginning of the file then read in how many animations there are to tempi
fin>>temps>>tempi;
m_animations.resize(tempi); // Resize the vector to the number of animations there are
getline(fin,temps);
for(int i=0; i<m_animations.size(); i++)
{
getline(fin,temps); // Read the folder name for the animation
m_animations.at(i).name=temps; // Assign the folder name to the animations name
std::cout<<"Animation "<<i<<". "<<m_animations.at(i).name<<std::endl;
}
std::cout<<std::endl;




I've also added some debug text that goes to stdout.txt... I'll post the new load and draw functions...

One thing...now I only get the error 2/10 times, I don't know why. But even when I don't get the error nothing gets draw on the screen...
I also tested comment out the animation part of the drawing function an tried to draw the first image of the first animation, but it didn't work.

Here's the new functions:

// This function loads a sprite from a directory, first it checks how many different animations
// the sprite has, then loads the frames of every animation. The width and height of the sprite
// is decided by the first of the first animation
bool sprite::load(std::string dir, SDL_Surface *dest)
{
// Temporary variables to receive the file input
std::string temps;
int tempi;
// Make a string by adding the dir and a specified file
std::string file=dir+"/animations.info";
std::ifstream fin; // Our fstream object, read only
fin.open(file.c_str()); // Open the file
if(fin==NULL) { return false; } // Return if the file don't exist or some other error
else
{
// Read by the "Animations:" string in the beginning of the file then read in how many animations there are to tempi
fin>>temps>>tempi;
m_animations.resize(tempi); // Resize the vector to the number of animations there are
getline(fin,temps);
for(int i=0; i<m_animations.size(); i++)
{
getline(fin,temps); // Read the folder name for the animation
m_animations.at(i).name=temps; // Assign the folder name to the animations name
std::cout<<"Animation "<<i<<". "<<m_animations.at(i).name<<std::endl;
}
std::cout<<std::endl;
}
fin.close(); // We are done with this file
fin.clear(); // We clear the handle to be able to open a new file with the same handle

// In this loop we'll load the frames of every animation
for(int i=0; i<m_animations.size(); i++)
{
// Make a filename of the dir and the name of the animation and the file containing the frames data
// Example: dir="gfx/sprites/hero" animation name="walkleft" then the whole path becomes:
// "gfx/sprites/hero/walkleft/frames.info"
file=dir+"/"+m_animations.at(i).name+"/frames.info";
fin.open(file.c_str()); // Open the file
if(fin==NULL) { return false; } // Exit if something unexpected happens
else
{
fin>>temps>>tempi; // Read past the "Frames:" string in the file and read the number of frames this animation has
m_animations.at(i).frames.resize(tempi); // Resize the vector to have place for all the frames
// This loop goes trough all the filenames and loads the frame image to it's surface
for(int k=0; k<m_animations.at(i).frames.size(); k++)
{
fin>>temps>>tempi; // Read the filename and the delay for the frame
std::string img; // Another temporary string to load the image
img=dir+"/"+m_animations.at(i).name+"/"+temps; // We do the same thing as above, make a whole path for the file
m_animations.at(i).frames.at(k).img=load_IMG(img); // Load the image and convert it to the format SDL uses
std::cout<<"Frame "<<k<<" of animation "<<i<<" has the path: "<<img<<" and the delay "<<tempi<<std::endl;
if(m_animations.at(i).frames.at(k).img==NULL) { std::cerr<<"The frame: "<<img<<" couldn't be loaded!\n"; }
m_animations.at(i).frames.at(k).delay=tempi; // Set the delay for the frame
}
fin.close(); // We are done with the file
fin.clear(); // We clear the handle to be able to open a new file with the same handle
}
std::cout<<std::endl;
}
m_rect.x=0; // Set the x value to 0
m_rect.y=0; // Set the y value to 0
// Set the width and height of the sprite to the width and height of the first frame of the first animation
m_rect.w=m_animations.at(0).frames.at(0).img->w;
m_rect.h=m_animations.at(0).frames.at(0).img->h;
m_animation=0; // Use the first animation
std::cout<<"\nThe width of the first frame of the first animation: "<<m_rect.w<<std::endl;
return true;
}

// This function draws the sprite, it animates automatically, if it isn't paused
void sprite::draw()
{
if(m_paused==false) // Check if the sprite animation is paused
{
// Check if the time we showed the last frame + the delay of this frame is greater or equal to SDL_GetTicks()
if(m_lastframe+m_animations.at(m_animation).frames.at(m_animations.at(m_animation).framenr).delay>=SDL_GetTicks())
{
// If ot is change to the next frame
m_animations.at(m_animation).framenr++;
// If it is the last frame of the animation we'll loop it, setting the framenr to the the first frame
if(m_animations.at(m_animation).framenr==m_animations.at(m_animation).frames.size())
{
m_animations.at(m_animation).framenr=0;
}
m_lastframe=SDL_GetTicks(); // We showed this frame now, save the time
}
}

// Blit the frame to the surface we assigned the sprite to
SDL_BlitSurface(m_animations.at(m_animation).frames.at(m_animations.at(m_animation).framenr).img, NULL, m_dest, &m_rect);
}




By the way, JWindebank I could mail you my sprite file if you'd like.

//walle

Share this post


Link to post
Share on other sites
Ok...I figured out the problem...and I just want to say: I'm an idiot!
In the line where I check if the frame is the last one...I check if the frame number is equal to the size of the frames vector...
But there aren't a last frame, so you have to check for size()-1...

Well it only took a complete rewrite to figure that out...

Now only to get a decent timing on the sprites...becuse this one doesn't work...

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!