• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Jamie_Edwards

SDL2 Not Loading/Showing Images?

17 posts in this topic

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.

Edited by Jamie_Edwards
0

Share this post


Link to post
Share on other sites

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
}
0

Share this post


Link to post
Share on other sites

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" );
Edited by exOfde
0

Share this post


Link to post
Share on other sites


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.

0

Share this post


Link to post
Share on other sites
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. Edited by dejaime
0

Share this post


Link to post
Share on other sites

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]

0

Share this post


Link to post
Share on other sites

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.

1

Share this post


Link to post
Share on other sites

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

0

Share this post


Link to post
Share on other sites

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

 

I declared it because I thought it would be easier to write "gui.keyPressSurfaces[]" rather than "Gui::keyPressSurfaces" as I have at least 5 points in my code where I have to write that. And same goes for Input too in the Event class ( if that makes sense ).

 

But changing the event calls to "Gui::" instead just makes the compiler vomit the following error:

error: invalid use of non-static data member 'Gui::keyPressSurfaces'

changing the "Gui::" back to "gui." and then changing "input." to "Input::" causes no errors.

 

Edit:

 

I changed everything to read:

 

Event.cpp ( with changes to KEY_PRESS_SURFACE_... to match what I wanted it to look like ):

Gui::currentSurface = Gui::keyPressSurfaces[Input::KEY_PRESS_SURFACE_DEFAULT];

 

Gui.h:

SDL_Surface* keyPressSurfaces[];
SDL_Surface* currentScreen;
 
// To:
static SDL_Surface* keyPressSurfaces[];
static SDL_Surface* currentScreen;

 

the compiler then gives:

undefined reference to 'Gui::currentSurface'
Edited by Jamie_Edwards
0

Share this post


Link to post
Share on other sites

You'll have to use the same Gui variable that you called initGui() on. Otherwise you're not using the window and surfaces that you created during initialization.

0

Share this post


Link to post
Share on other sites

You are using a non-initialized Gui object on Event.cpp.

Every time you call the event( SDL_Event* ) function, you create a new Gui and use it without loading anything.

In the end of the function call, it is deleted.

So, as Yellowsputnik pointed out, you're not using the Gui object you think you are.

 

You could pass on the Gui object to the event function as in here:

void Initialize::event ( const Gui &gui, SDL_Event* event )

or even use a global variable for it.

 

What exactly is the Initialize class responsible for?

Edited by dejaime
1

Share this post


Link to post
Share on other sites


You are using a non-initialized Gui object on Event.cpp.
Every time you call the event( SDL_Event* ) function, you create a new Gui and use it without loading anything.
In the end of the function call, it is deleted.
So, as Yellowsputnik pointed out, you're not using the Gui object you think you are.

 

Right ok.

 


You could pass on the Gui object to the event function as in here:
void Initialize::event ( const Gui &gui, SDL_Event* event )
or even use a global variable for it.

 

I tried doing as you said and I think I did it wrong as it threw errors at me. Could you show me how it should be implemented?

 


What exactly is the Initialize class responsible for?

 

It's responsible for pretty much everything, it initializes the event loop, gui, render and finally the cleanup when the app is closed.

0

Share this post


Link to post
Share on other sites

Could you show me how it should be implemented?

 
Take a look at the following code snippet:
#include <iostream>

class MyClass {
	std::string myName;
	
public:
	MyClass(std::string name): myName(name){
            //myName = name;
        }

	void PrintMyName() {
		std::cout << myName << std::endl;
	}
};

void CallPrintMyName (MyClass& correct_object) {
	correct_object.PrintMyName();
}

int main (){
        // Creates two objects with their names.
        MyClass Dejaime("Dejaime Neto"), JohnSmith("John Smith");

        //Call the function passing the first object
	CallPrintMyName (Dejaime);
        //Call again with the second one
	CallPrintMyName (JohnSmith);
}
You see, I pass on the object I want to use inside the CallPrintMyName function.
It outputs the following:
>> Dejaime Neto
>> John Smith

If you want some advice, it just seems you are biting a bit more than you can chew at the moment. I'd advise you to take a step back and study a bit more variable scopes, functions and object orientation in general, be it with Java or C++. Give it a week or so and then get back to this problem, it can only do good! Edited by dejaime
2

Share this post


Link to post
Share on other sites

OK, I've decided to follow the tutorial a little closer to get the gist of how to make SDL work, but it's still not working properly. It builds and runs fine, but when I ask it to load a ".bmp" image, it just shows a white surface.

 

I've tried putting the image in with the "Initialize.cpp", "main.cpp", "Gui.cpp" and in the root directory, and even in the bin/debug folder and it still comes up with a just a white screen.

0

Share this post


Link to post
Share on other sites

Make sure to check return values of functions to see if they actually did what you think they should do.

 

When debugging, I always like to use breakpoints and step through the code to know exactly what's going on. You can try that here as well.

0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0