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 explanedint 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) { returnfalse; } // 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 animationfor(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) { returnfalse; } // 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
}
returntrue;
}
// 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;
}

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 filefin.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.

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) { returnfalse; } // 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 animationfor(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) { returnfalse; } // 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;returntrue; }

// 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

0

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...