С++ Allegro 5 - не удается найти источник нарушения доступа

Я работаю над игрой на С++, используя Allegro 5. Из руководств, в которых весь код помещался в main.cpp, казалось, что он работает нормально. С тех пор я организовал код в классы, но теперь я сталкиваюсь с этой ошибкой во время выполнения:

«Исключение первого шанса по адресу 0x57052F4B (allegro-5.0.10-monolith-mt-debug.dll) в Face Chase Allegro5.exe: 0xC0000005: местоположение чтения нарушения прав доступа 0x00000000. Необработанное исключение по адресу 0x57052F4B (allegro-5.0.10-monolith- mt-debug.dll) в Face Chase Allegro5.exe: 0xC0000005: место чтения с нарушением прав доступа 0x00000000. Программа «[6020] Face Chase Allegro5.exe» завершила работу с кодом 0 (0x0)».

Вот некоторый справочный код:

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);    
}

Менеджер сцен.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);
}

основной.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 сообщает мне, что проблема в конструкторе SceneManager.cpp. Во-первых, ему не нравится m_display. Если я закомментирую эту строку, ей не понравится m_background. Я комментирую это, ему не нравится m_titleScreen, и он выдает мне одинаковую ошибку для каждого из этих изменений. Так что я совершенно озадачен, в чем здесь проблема. Любые идеи?


person Agent Baron    schedule 18.03.2014    source источник
comment
Некоторый код отсутствует, например GameManager::getInstance(). Вы можете создать экземпляр GameManager без new, как переменную в main. - Как Visual Studio выражает свою неприязнь?   -  person laune    schedule 18.03.2014
comment
Я только добавил справочный код; это не вся программа. Я обновлю свой пост остальной частью кода, если вы действительно хотите, но это совсем не относится к моей проблеме. getInstance() принадлежит шаблону Singleton, из которого получен GameManager. Ошибка, которую я получаю от Visual Studio, находится в первой части моего поста.   -  person Agent Baron    schedule 18.03.2014
comment
Поскольку никто больше не пытается помочь, я могу только предположить, что адреса, такие как 0x57052F4B или 0xC0000005, могут быть интерпретированы чем-то, известным как карта компоновщика, показывающая, где каждый объектный модуль загружается в файле .exe. Это может пролить свет на местонахождение ошибки. Кроме этого: убедитесь, что все, что должно возвращать указатель (а у вас много таких вызовов), не возвращает указатель NULL. Ни в коем случае не доверяйте какому-либо коду, который должен возвращать указатель на объект, что он всегда будет возвращать действительное, то есть ненулевое значение.   -  person laune    schedule 18.03.2014
comment
До сих пор мне удавалось понять, что программа просто падает всякий раз, когда я использую al_create_display() и al_load_bitmap(). Однако, почему он дает мне указатели NULL, я не понимаю. Надеюсь, кто-то может помочь, а пока я буду продолжать молоть.   -  person Agent Baron    schedule 19.03.2014


Ответы (1)


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

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

Это всего лишь предположение, но это выглядит как опасный код. al_init() должен вызываться перед (почти) каждым другим методом Allegro.

Убедитесь, что вы не вызываете какой-либо метод Allegro до того, как будут вызваны его обязательные методы инициализации.

person Matthew    schedule 19.03.2014