I started creating a game in Visual Studio 2017 in C++ using Allegro 5. In order to make it easier to manage images, I created an ImageLoader class which would load and store all active images, and destroy them as necessary. It does so using a map which matches filenames to the corresponding images. Currently my main() code looks like this:
int main(){
if (!al_init()) {
al_show_native_message_box(NULL, NULL, NULL, "Could not intialize allegro 5.", NULL, NULL);
return -1;
}
ALLEGRO_DISPLAY *display = al_create_display(DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT);
al_set_window_title(display, "Game title");
// make usre the display was created correctly
if (!display) {
al_show_native_message_box(display, "Title", "settings", "Could not create Allegro window.", NULL, NULL);
}
// intialize fonts, primitives, keyboard,etc.
al_init_font_addon();
al_init_ttf_addon();
al_init_primitives_addon();
al_install_keyboard();
if(!al_init_image_addon()) {
al_show_native_message_box(display, "Error", "Error", "Failed to initialize al_init_image_addon!",
NULL, ALLEGRO_MESSAGEBOX_ERROR);
return -1;}
ImageLoader image_loader;
The ImageLoader then loads an image for the player:
ALLEGRO_BITMAP *image = al_load_bitmap(filename);
if (image == NULL) {
std::cout << filename << std::endl;
std::cout << "loader failed to load image" << std::endl;
}
image_map[filename] = image;
When I test this part, it seems to work, as the image is not null. Note that image_map is declared like so in ImageLoader.h:
std::map<const char *, ALLEGRO_BITMAP*> image_map;
The problem arises in my main game loop when I then try to get the image from the ImageLoader:
for (GameImage image : imageList) {
ALLEGRO_BITMAP *draw_image = image_loader.get_current_image(image);
if (draw_image == NULL) {
//TODO: error handling
std::cout << "no image" << std::endl;
}
else
al_draw_bitmap(draw_image, image.get_x(), image.get_y(), NULL);
}
My check always shows that draw_image
is null. Here is the code for get_current_image:
ALLEGRO_BITMAP * ImageLoader::get_current_image(GameImage image)
{
return image_map[image.get_image_filename()];
}
I have tested to make sure I'm using the same filename here as when I load the image and store it in the map by checking if (image_map.find(image.get_image_filename()) == image_map.end())
, but even though this returns false the ALLEGRO_BITMAP pointer is still null. I have tried making the map store bitmaps instead of pointers, but this gives me an error when I try to add an element to the map since I'm not allowed to modify map values like this. Why might these pointers become null in between the time where I set them and the time where I retrieve them? I'm also open to other suggestions for how I should store my bitmaps.
EDIT: I revised my project, changing the instances of filenames as char arrays to std::strings. The image map is now declared as std::map<std::string, ALLEGRO_BITMAP*> image_map
in ImageLoader.h, and the filename stored by GameImage is now std::string image_filename
. load_image
in ImageLoader.cpp now looks like this:
ALLEGRO_BITMAP *image = al_load_bitmap(filename.c_str());
if (image == NULL) {
std::cout << filename << std::endl;
std::cout << "loader failed to load image" << std::endl;
}
image_map[filename] = image;
Finally, get_current_image
is still the same:
ALLEGRO_BITMAP * ImageLoader::get_current_image(GameImage image)
{
return image_map[image.get_image_filename()];
}
However, the same problem still persists. I have also checked the size of the image map and it stays at 1 throughout the duration of my program, with the filename for the image I insert as the key and the value starting as a non-null pointer to an bitmap and appearing to become null at some point.
EDIT 2:
After changing the char arrays to strings and fixing get_current_image()
so that it no longer adds to the map if the searched filename is not found, I discovered that I had also made a mistake when loading the images in a line I'd forgotten to include when I initially posted the question:
current_screen.load_images(image_loader);
As it turned out, I had written load_images()
like so:
void MainGameScreen::load_images(ImageLoader loader)
...meaning that the calls the function made to loader
weren't actually applying to the ImageLoader I'd passed in. I changed it to:
void MainGameScreen::load_images(ImageLoader& loader)
...and now everything works fine.