Question

I'm working on a game in C++ using Allegro 5. From tutorials that placed all code in main.cpp, it seemed to work fine. I've since organized the code into classes, but I'm now encountering this error at runtime:

"First-chance exception at 0x57052F4B (allegro-5.0.10-monolith-mt-debug.dll) in Face Chase Allegro5.exe: 0xC0000005: Access violation reading location 0x00000000. Unhandled exception at 0x57052F4B (allegro-5.0.10-monolith-mt-debug.dll) in Face Chase Allegro5.exe: 0xC0000005: Access violation reading location 0x00000000. The program '[6020] Face Chase Allegro5.exe' has exited with code 0 (0x0)."

Here is some reference code:

GameManager.h:

#pragma once

#include <allegro5\allegro.h>
#include "Singleton.h"
#include "SceneManager.h"
#include "InputManager.h"

typedef enum GAMESTATE { TITLE, MAIN, GAME_OVER };

class GameManager : public Singleton<GameManager>
{
private:
    SceneManager* m_SceneManager; //manages the level and visual elements
    InputManager* m_InputManager; //manages input variables

    GAMESTATE m_gameState; //whether or not the game is at the title, main game, game over, etc.

    ALLEGRO_EVENT_QUEUE* m_queue; //event queue, used for storing events to al_event
    ALLEGRO_TIMER* m_timer; //timer for regulating FPS

    bool m_gameEnd; //for keeping track of whether or not the program should close
    bool m_redraw; //when certain conditions are met, the program will redraw the screen

protected:
    Singleton<GameManager> *m_GameManager;

public:
    GameManager();
    ~GameManager();

    SceneManager* getSceneManager() {return m_SceneManager;}

    GAMESTATE getGameState() {return m_gameState;}

    ALLEGRO_EVENT_QUEUE* getEventQueue() {return m_queue;}
    ALLEGRO_TIMER* getTimer() {return m_timer;}

    bool getGameEnd() {return m_gameEnd;}
    bool getRedraw() {return m_redraw;}

    void setGameState(GAMESTATE newState) {m_gameState = newState;}

    void setQueue(ALLEGRO_EVENT_QUEUE* queue) {m_queue = queue;}
    void setTimer(ALLEGRO_TIMER* timer) {m_timer = timer;}

    void setGameEnd(bool gameEnd) {m_gameEnd = gameEnd;}

    void doControl(ALLEGRO_EVENT* ev);
};

GameManager.cpp:

#include "GameManager.h"

const int FPS = 60;

GameManager::GameManager() //This is where I encounter access violations at 0x00000000
{
    m_SceneManager = new SceneManager;
    m_InputManager = new InputManager;

    m_gameState = TITLE; //when the program runs it starts at the title screen

    m_queue = al_create_event_queue();
    m_timer = al_create_timer(1.0 / FPS);

    m_gameEnd = false;
    m_redraw = false;
}

GameManager::~GameManager()
{
    delete m_SceneManager;
    m_SceneManager = NULL;

    delete m_queue;
    m_queue = NULL;

    delete m_timer;
    m_timer = NULL;
}

void GameManager::doControl(ALLEGRO_EVENT* ev)
{
    if (ev->type == ALLEGRO_EVENT_MOUSE_AXES)
        m_InputManager->setMousePos(ev->mouse.x, ev->mouse.y);
    //code for tracking the mouse position; I plan to add button functionality and
    //a custom cursor to the title screen in due time

    if (ev->type == ALLEGRO_EVENT_DISPLAY_CLOSE ||
        (ev->type == ALLEGRO_EVENT_KEY_DOWN && ev->keyboard.keycode == ALLEGRO_KEY_ESCAPE))
        setGameEnd(true);
    //instructs the program to close if the user clicks close or presses escape

    switch (getGameState()) //gets the game state for evaluation
    {
    case TITLE: //event handling for the title screen
        {
            if((ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN && ev->mouse.button &1) ||
                (ev->type == ALLEGRO_EVENT_KEY_DOWN && ev->keyboard.keycode == ALLEGRO_KEY_ENTER))
                setGameState(MAIN);
            break;  //if the left button is clicked or enter is pressed, starts the main game
        }

    case MAIN: //event handling for main game
        {
            switch (ev->type)
            {
            case ALLEGRO_EVENT_KEY_DOWN:
                switch (ev->keyboard.keycode) //handles movement of player character
                {
                case ALLEGRO_KEY_UP:
                    {
                        m_InputManager->setKeys(UP, true);
                        break;
                    }
                case ALLEGRO_KEY_DOWN:
                    {
                        m_InputManager->setKeys(DOWN, true);
                        break;
                    }
                case ALLEGRO_KEY_RIGHT:
                    {
                        m_InputManager->setKeys(RIGHT, true);
                        break;
                    }
                case ALLEGRO_KEY_LEFT:
                    {
                        m_InputManager->setKeys(LEFT, true);
                        break;
                    }
                }

            case ALLEGRO_EVENT_KEY_UP:
                {
                    switch (ev->keyboard.keycode)
                    {
                    case ALLEGRO_KEY_UP:
                        {
                            m_InputManager->setKeys(UP, false);
                            break;
                        }
                    case ALLEGRO_KEY_DOWN:
                        {
                            m_InputManager->setKeys(DOWN, false);
                            break;
                        }
                    case ALLEGRO_KEY_RIGHT:
                        {
                            m_InputManager->setKeys(RIGHT, false);
                            break;
                        }
                    case ALLEGRO_KEY_LEFT:
                        {
                            m_InputManager->setKeys(LEFT, false);
                            break;
                        }
                    }
                }
            }
        }
    }

    bool collision;
    bool* tempKeys[3];

    for (int i = 0; i < 4; i++)
        *tempKeys[i] = m_InputManager->getKey(i);
    //updates keys array and player data
    m_SceneManager->updateEntityCoords(tempKeys, collision);    
}

SceneManager.h:

#pragma once

#include <iostream>

#include <allegro5\allegro.h>
#include <allegro5\allegro_audio.h>
#include <allegro5\allegro_acodec.h>
#include "InputManager.h"
#include "Entity.h"

class SceneManager
{
private:
    ALLEGRO_DISPLAY* m_display; //main window display

    ALLEGRO_BITMAP* m_background; //background during the main game
    ALLEGRO_BITMAP* m_titleScreen; //title screen image

    ALLEGRO_SAMPLE* m_titleMusic;
    ALLEGRO_SAMPLE* m_bgMusic;     //various sound assets
    ALLEGRO_SAMPLE* m_soundDog;
    ALLEGRO_SAMPLE* m_soundEat;

    Entity* m_face; //player entity
    Entity* m_poop;//poop entity

public:
    SceneManager();
    ~SceneManager();

    ALLEGRO_DISPLAY* getDisplay() {return m_display;}

    ALLEGRO_BITMAP* getBackground() {return m_background;}
    ALLEGRO_BITMAP* getTitleScreen() {return m_titleScreen;}

    ALLEGRO_SAMPLE* getTitleMusic() {return m_titleMusic;}
    ALLEGRO_SAMPLE* getBGM() {return m_bgMusic;}
    ALLEGRO_SAMPLE* getSoundDog() {return m_soundDog;}
    ALLEGRO_SAMPLE* getSoundEat() {return m_soundEat;}

    Entity* getFace() {return m_face;}
    Entity* getPoop() {return m_poop;}

    void setDisplay(ALLEGRO_DISPLAY* display) {m_display = display;}

    void setFace(Entity newFace) {*m_face = newFace;}
    void setPoop(Entity newPoop) {*m_poop = newPoop;}

    bool isCollision(Entity* entity1, Entity* entity2); //returns true if there is a collision
    void updateEntityCoords(bool* keys[3], bool collision); //adjust player coordinates and moves the poop if it is collected
    void UpdateHitbox(Entity* entity, EntityType type); //updates entity hitboxes

    void BuildBackground(ALLEGRO_BITMAP* background); //builds the entire background from a single tile

    void playTitleMusic()
    {al_play_sample(m_titleMusic, 255, 128, 1000, ALLEGRO_PLAYMODE_LOOP, NULL);}
    //title music loop when the program starts

    void playMainSounds(); //main game sound loop

    void updateDisplay(); //redraws the screen with updated data
};

SceneManager.cpp:

#include "SceneManager.h"

const int screenWidth = 640;
const int screenHeight = 480;

SceneManager::SceneManager()
{
    m_display = al_create_display(screenWidth, screenHeight); //creates a 640 x 480 display

    m_background = al_create_bitmap(640, 480);
    m_titleScreen = al_load_bitmap("assets/title.bmp");

    m_soundDog = al_load_sample("assets/dog.wav");
    m_bgMusic = al_load_sample("assets/music.wav");
    m_soundEat = al_load_sample("assets/eat.wav");
    m_titleMusic = al_load_sample("assets/title.wav");

    m_face = new Entity(FACE);
    m_poop = new Entity(POOP);
}

SceneManager::~SceneManager()
{
    delete m_display;
    m_display = NULL;

    delete m_background;
    m_background = NULL;

    delete m_titleScreen;
    m_titleScreen = NULL;

    delete m_titleMusic;
    m_titleMusic = NULL;

    delete m_bgMusic;
    m_bgMusic = NULL;

    delete m_soundDog;
    m_soundDog = NULL;

    delete m_soundEat;
    m_soundEat = NULL;

    delete m_face;
    m_face = NULL;

    delete m_poop;
    m_poop = NULL;
}

bool SceneManager::isCollision(Entity* entity1, Entity* entity2)
{
    if (entity1->getHitbox()->x < entity2->getHitbox()->w &&
        entity1->getHitbox()->y < entity2->getHitbox()->h &&
        entity1->getHitbox()->w > entity2->getHitbox()->x &&
        entity1->getHitbox()->h > entity2->getHitbox()->y)
        return true;
    else
        return false;
}

void SceneManager::updateEntityCoords(bool* keys[3], bool collision)
{
    getFace()->setY(getFace()->getY() - (*keys[UP] * 7));
    getFace()->setY(getFace()->getY() + (*keys[DOWN] * 7));
    getFace()->setX(getFace()->getX() - (*keys[LEFT] * 7));
    getFace()->setX(getFace()->getX() + (*keys[RIGHT] * 7));

    if (collision) //moves poop in case of collision
    {
        getFace()->setScore(getFace()->getScore() + 1);

        getPoop()->setX(rand() % 448);
        getPoop()->setY(rand() % 608);
    }
}

void SceneManager::UpdateHitbox(Entity* entity, EntityType type)
{
    switch (type)
    {
    case FACE:
        {
            entity->setHitbox(entity->getX(),
                              entity->getY(),
                              entity->getX() + 64,
                              entity->getY() + 64);
            break;
        }
    case POOP:
        {
            entity->setHitbox(entity->getX(),
                              entity->getY(),
                              entity->getX() + 32,
                              entity->getY() + 32);
            break;
        }
    }
}

void SceneManager::BuildBackground(ALLEGRO_BITMAP* background)
{
    ALLEGRO_BITMAP *bgtile = al_load_bitmap("assets\bg.bmp");
    al_set_target_bitmap(background);
    //creates a struct of type ALLEGRO_BITMAP and sets Allegro's draw
    //target to it

    for(int i = 0; i <= 640; i++)
    {
        if(i % 32 == 0)
        {
            for(int j = 0; j <= 480; j++)
            {
                if(j % 32 == 0)
                {
                    al_draw_bitmap(bgtile, 0, 0, NULL);
                    std::cout << "Placed tile at " << i << ", " << j << "\n";
                }
            }
        }
    }

    al_destroy_bitmap(bgtile); //destroys bgtile since the background is generated
                               //and bgtile will no longer be needed

}

void SceneManager::playMainSounds()
{
    al_stop_samples(); //stops looping title music and plays main game music
    al_play_sample(m_soundDog, 255, 128, 1000, ALLEGRO_PLAYMODE_ONCE, NULL);
    al_play_sample(m_bgMusic, 255, 128, 1000, ALLEGRO_PLAYMODE_LOOP, NULL);
}

void SceneManager::updateDisplay()
{
    al_set_target_backbuffer(getDisplay()); //sets target back to display's back buffer and draws the objects to it
    al_draw_bitmap(m_background, 0, 0, NULL);
    al_draw_bitmap(m_face->getSprite(), m_face->getX(), m_face->getY(), NULL);
    al_draw_bitmap(m_poop->getSprite(), m_poop->getX(), m_poop->getY(), NULL);
}

main.cpp:

#include <allegro5\allegro.h>
#include <allegro5\allegro_font.h>
#include <allegro5\allegro_ttf.h>
#include <allegro5\allegro_primitives.h>

#include "GameManager.h"

int main(void)
{
    GameManager* manager = GameManager::getInstance();
    //create game manager

    if (!al_init()) //returns a value of -1 if
        return -1;  //Allegro does not initialize properly

    if (!manager->getSceneManager()->getDisplay()) //returns -1 if the display window is
        return -1;              //not initialized properly

    al_init_primitives_addon(); //allows for drawing basic shapes via functions
    al_init_font_addon();       //allows for drawing text to the screen
    al_init_ttf_addon();        //allows for drawing true type fonts
    al_install_keyboard();      //gets input from keyboard
    al_install_mouse();         //gets input from mouse


    //registers display, keyboard, mouse, and timer as sources of events
    al_register_event_source(manager->getEventQueue(), al_get_display_event_source(manager->getSceneManager()->getDisplay()));
    al_register_event_source(manager->getEventQueue(), al_get_keyboard_event_source());
    al_register_event_source(manager->getEventQueue(), al_get_mouse_event_source());
    al_register_event_source(manager->getEventQueue(), al_get_timer_event_source(manager->getTimer()));

    //starts timer for regulating FPS
    al_start_timer(manager->getTimer());

    //start of main loop
    while (!manager->getGameEnd())
    {
        ALLEGRO_EVENT al_event;
        al_wait_for_event(manager->getEventQueue(), &al_event);
        //creates an event that catches things that happen such as key presses and mouse clicks
        //and then instructs the program to wait for one of these things to happen and store it
        //to al_event

        manager->getSceneManager()->updateDisplay(); //update window display
        manager->doControl(&al_event); //handles input and updates data accordingly
    }
}

Visual Studio is telling me the issue is in SceneManager.cpp's constructor. First it doesn't like m_display. If I comment that line out, it doesn't like m_background. I comment that out, it doesn't like m_titleScreen and it's giving me an identical error for every one of these changes. So I'm completely stumped as to what the problem is here. Any ideas?

Was it helpful?

Solution

   GameManager* manager = GameManager::getInstance();
    //create game manager

    if (!al_init()) //returns a value of -1 if
        return -1;  //Allegro does not initialize properly

This is just guess, but that looks like dangerous code. al_init() must be called before (nearly) every other Allegro method.

Make sure you are not calling any Allegro method before its prerequisite init methods have been called.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top