Advertisement

SDL2 Not Loading/Showing Images?

Started by June 05, 2014 03:58 PM
16 comments, last by yellowsputnik 10 years, 7 months ago

Hi guys,

so I've decided to start trying to making a simple game using SDL2. I'd found a ( what seems to be good ) Tutorial by Lazy Foo... Problem is....

Either I'm a complete noob, or something just isn't working (note: I've not used C++ in about a year, and came over from Java).

This is what I have (also, this is my OOP approach to his tutorials, and I'll pick out the "problem" code):

Gui.h:

[spoiler]


class Gui {
private:
    ...
    SDL_Window* window;
    SDL_Surface* screenSurface;
public:
    SDL_Surface* keyPressSurfaces[];
    SDL_Surface* currentSurface;
 
public:
    Gui();
    void initGui();
    bool loadMedia();
    SDL_Surface* loadSurface ( std::string path );
    ...
};

[/spoiler]

Gui.cpp:

[spoiler]


Gui::Gui() {
    window = NULL;
    screenSurface = NULL;
    currentSurface = NULL;
    keyPressSurface[Input::KEY_PRESS_SURFACE_TOTAL]; // There is a compiler warning here saying "statement has no effect"????
}
 
void Gui::initGui() {
    window = SDL_CreateWindow ( .... ) // Creating the master window
    if ( window == NULL ) {

    }
    else {
        screenSurface = SDL_GetWindowSurface ( window ); // Get the window surface
 
        // set the default surface
        currentSurface = keyPressSurfaces[Input::KEY_PRESS_SURFACE_DEFAULT];
 
        // Apply the current surface
        SDL_BlitSurface ( currentSurface, NULL, screenSurface, NULL );
 
        // Update the surface
        SDL_UpdateWindowSurface ( window );
    }
}
 
bool Gui::loadMedia() {
    Input input;
 
    bool success = true;
 
    // Load default surface
    keyPressSurfaces[input.KEY_PRESS_SURFACE_DEFAULT] = loadSurface ( "assets/surfaces/press.jpg" );
    if ( keyPressSurfaces[input.KEY_PRESS_SURFACE_DEFAULT] == NULL ) {
        printf ( "Failed to load default image!\n" );
        success = false;
    }
 
    // I'll omit the code for the up, down, left and right key presses as they are all identical to the "load default surface" one above ( except for
    // the path )
    ...
 
    ...
 
    return success;
}
 
SDL_Surface* Gui::loadSurface ( std::string path ) {
    // Load image at specified path
    SDL_Surface* loadedSurface = SDL_LoadBMP ( path.c_str() );
 
   return loadedSurface;
}

[/spoiler]

Input.h:

[spoiler]


class Input {
public:
    enum Key_Press_Surfaces {
        KEY_PRESS_SURFACE_DEFAULT,
        ...
 
        ...
        KEY_PRESS_SURFACE_RIGHT,
        KEY_PRESS_SURFACE_TOTAL
    };
 
public:
    Input();
};

[/spoiler]

Event.cpp:

[spoiler]


void Initialize::event ( SDL_Event* event ) {
    Gui gui;
    Input input;
 
// User presses a key
else if ( Event -> type == SDL_KEYDOWN ) {
// Select surface based on key press
switch ( Event -> key.keysym.sym ) {
case SDLK_w :
gui.currentSurface = gui.keyPressSurfaces[input.KEY_PRESS_SURFACE_UP];
break;
 
case SDLK_s :
gui.currentSurface = gui.keyPressSurfaces[input.KEY_PRESS_SURFACE_DOWN];
break;
 
case SDLK_a :
gui.currentSurface = gui.keyPressSurfaces[input.KEY_PRESS_SURFACE_LEFT];
break;
 
case SDLK_d :
gui.currentSurface = gui.keyPressSurfaces[input.KEY_PRESS_SURFACE_RIGHT];
break;
 
default:
gui.currentSurface = gui.keyPressSurfaces[input.KEY_PRESS_SURFACE_DEFAULT];
break;
}
}

[/spoiler]

In my Initialize.cpp I've got the initGui function just before my event loop.

Oh and my dev tree is as follows:

[spoiler]

Tutorial ( root )
    assets/
        surfaces/
            press.bmp
            down.bmp
            left.bmp
            right.bmp
            up.bmp
    bin/
    includes/
        control/
            Input.h
        gui/
            Gui.h
        init/
            Initialize.h
        includes.h
    obj/
    src/
        control/
            Input.cpp
        gui/
            Gui.cpp
        init/
            Initialize.cpp
        main/
            main.cpp
        term/
            CleanUp.cpp
 

[/spoiler]

I don't understand what's going wrong, or I'm completely overlooking something, but that being said, when it's built and run, there are no error, except that one warning, and the surface goes black, so it's certainly doing something.

Any help would be much appreciated.

Thanks!

Jamie.

Do you call SDL_Init anywhere?

 

Advertisement

Do you call SDL_Init anywhere?

Yes, in Initialize.cpp, I have an if else statement that says:

if ( SDL_Init ( SDL_INIT_VIDEO ) < 0 ) {
    printf ( "SDL could not initialize! SDL_ERROR: %s\n", SDL_GetError() );
    return -1;
}
else {
    // initiate the game here
}

class Gui {
private:
...
SDL_Window* window;
SDL_Surface* screenSurface;
public:
SDL_Surface* keyPressSurfaces[];

in your GUI class. you declare a pointer to an array, or a pointer to a pointer. but you never initilize it. so from where take you your surfaces?

of course you load it with GUI::loadMedia but even there you just access the first pointer to the array which you has never initilized yet and try to assign a new value to it

perhaps i am wrong but that what i see ...


bool Gui::loadMedia() {
Input input;

bool success = true;

// Load default surface
keyPressSurfaces[input.KEY_PRESS_SURFACE_DEFAULT] = loadSurface ( "assets/surfaces/press.jpg" );


in your GUI class. you declare a pointer to an array, or a pointer to a pointer. but you never initilize it. so from where take you your surfaces?
of course you load it with GUI::loadMedia but even there you just access the first pointer to the array which you has never initilized yet and try to assign a new value to it

perhaps i am wrong but that what i see ...

I do initialize them. If you look in the Gui.cpp spoiler, at the "Gui::Gui()" method, I initialize them there.

keyPressSurface[Input::KEY_PRESS_SURFACE_TOTAL]; // There is a compiler warning here saying "statement has no effect"????
This means your code isn't doing anything. The above line is the same as the example below:
int myVar; // Creates the variable
myVar; // This isn't doing anything at all, you're referencing something but not doing anything to/with it.
In this code (from Gui.h):
public:
    SDL_Surface* keyPressSurfaces[];
This pointer isn't being initialized anywhere. You need to allocate some memory for it before using, adding the below to your Gui::Gui() may fix your problem
// Define the total number of surfaces desired somehow ...
#define TOTAL_SURFACES 20
// and allocate this number times the size of a surface.
keyPressSurface = (SDL_Surface**)malloc( TOTAL_SURFACES * Sizeof(SDL_Surface) );

//OR declare it like this if you know beforehand how many surfaces you want:
public:
    SDL_Surface* keyPressSurfaces[TOTAL_SURFACES];
//One or the other, the first uses dynamic memory and the second static.
But remember to clean up in your Gui::~Gui()
//CleanUp
if (keyPressSurface)
    free(keyPressSurface);
@edit
    enum Key_Press_Surfaces {
        KEY_PRESS_SURFACE_DEFAULT,
        ...
        KEY_PRESS_SURFACE_RIGHT,
        KEY_PRESS_SURFACE_TOTAL
    };
As I can see, you're relying on enum to result in integer values, so you can use them as indexes for the array. You shouldn't do that though, enum isn't guaranteed to result in an ordered set of integers.

You could give it explicit values though, as in here:
    enum Key_Press_Surfaces {
        KEY_PRESS_SURFACE_DEFAULT = 0,
        ... //incrementing by 1
        KEY_PRESS_SURFACE_RIGHT = 9,
        KEY_PRESS_SURFACE_TOTAL = 10
    };
Of course there is the possibility of creating a custom safe enum for your projects using templates, but that is a bit too complex and I personally don't think I could do it to exemplify here without spending some hours with it.
Advertisement

what dejaime wrote was what i actually meant

OK, the errors and warnings have gone! BUT...

When I tried to do the following:


keyPressSurface = (SDL_Surface**)malloc( TOTAL_SURFACES * Sizeof(SDL_Surface) );

it didn't like "SDL_Surface**" but when I replaced that with "SDL_Surface*" it compiled fine. so my code now looks like this:

Gui.h:

[spoiler]

class GUI {
    // Defines for the display surfaces
    #define TOTAL_SURFACES 10
 
    ...
 
    ...
public:
    SDL_Surface* keyPressSurfaces[];
    SDL_Surface* currentSurface;
};

[/spoiler]

Gui.cpp:

[spoiler]

Gui::Gui() {
    ...
 
    ...
    // Allocate the TOTAL_SURFACE * the size of a surface
    keyPressSurfaces[Input::KEY_PRESS_SURFACE_TOTAL] = ( SDL_Surface* ) malloc ( TOTAL_SURFACES * sizeof ( SDL_Surface ) );
 
    // Clean the above up
    if ( keyPressSurfaces )
        free ( keyPressSurfaces );
}

[/spoiler]

As said, the above are no longer kicking out any errors or warnings. Thing is, when the game is built and run, I still get a black window and no reaction to ANY input given by the keyboard.

Could it be that I've got my images in the wrong place because at the moment I have my assets folder in the root of the project?

oh and also, I've done the edit you suggested:

Input.h:

[spoiler]

class Input {
public:
    enum Key_Press_Surfaces {
        KEY_PRESS_SURFACE_DEFAULT = 0,
        KEY_PRESS_SURFACE_UP = 0,
        ...
 
        ...
        KEY_PRESS_SURFACE_TOTAL = 5
    };
public:
    Input();
};

[/spoiler]

Why do you declare a Gui variable in Initialize::event()?

Is that the actual Gui object that you use in the rest of the program? My guess is that you're not working with the Gui object that you think you're using.

 

Btw, you can also use Input::KEY_PRESS_SURFACE_UP instead of defining a local Input object and using input.KEY_PRESS_SURFACE_UP.

 

This topic is closed to new replies.

Advertisement