2017-05-02 12 views
0

Allegro 5를 사용하여 C++에서 Visual Studio 2017로 게임을 만들기 시작했습니다. 이미지를 더 쉽게 관리 할 수 ​​있도록 ImageLoader 클래스를 만들었습니다.이 클래스는 모든 활성 이미지를 만들고 필요에 따라 이미지를 파괴하십시오. 파일 이름을 해당 이미지와 일치시키는 맵을 사용합니다. 현재 내 주() 코드는 다음과 같습니다Allegro 5 : 표준 맵에 비트 맵을 저장하는 데 문제가 있습니다

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; 

이하여 ImageLoader 다음 플레이어에 대한 이미지로드 :

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; 

나는이 부분을 테스트

, 작동하는 것 같다을, 이미지 그대로 null이 아닙니다. 그 image_map는 ImageLoader.h 년과 같이 선언 참고 :

항상
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); 

     } 

내 체크 쇼 : 나는 다음하여 ImageLoader에서 이미지를 얻을 때

std::map<const char *, ALLEGRO_BITMAP*> image_map; 

문제는 내 주요 게임 루프에서 발생 draw_image은 null입니다. 내가 테스트 한

ALLEGRO_BITMAP * ImageLoader::get_current_image(GameImage image) 
{ 
return image_map[image.get_image_filename()]; 
} 

가 나는 이미지를로드하고 if (image_map.find(image.get_image_filename()) == image_map.end())을 확인하여지도에 저장하지만,이 false를 반환하더라도 때 여기에 같은 파일 이름을 사용하고 있는지 확인하기 위해 다음과 같습니다 get_current_image의 코드는 ALLEGRO_BITMAP 포인터가 여전히 널입니다. 포인터 대신 비트 맵 맵 스토어를 만들려고했는데 이렇게 맵 값을 수정할 수 없기 때문에 맵에 요소를 추가하려고하면 오류가 발생합니다. 왜 내가이 포인터를 설정 한 시간과 내가 검색 한 시간 사이에이 포인터가 null이 될 수 있습니까? 또한 비트 맵을 저장하는 방법에 대한 다른 제안도 열려 있습니다.

편집 : 파일 배열의 인스턴스를 char 배열로 std :: strings로 변경하여 프로젝트를 수정했습니다. 이미지 맵은 이제 ImageLoader.h에 std::map<std::string, ALLEGRO_BITMAP*> image_map으로 선언되었으며 GameImage에 저장된 파일 이름은 이제 std::string image_filename입니다. ImageLoader.cpp에서 load_image 이제 다음과 같습니다

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; 

마지막으로, get_current_image는 여전히 동일합니다 :

ALLEGRO_BITMAP * ImageLoader::get_current_image(GameImage image) 
{ 
return image_map[image.get_image_filename()]; 
} 

그러나, 동일한 문제가 지속. 또한 이미지 맵의 크기를 확인한 후 내 프로그램 기간 동안 키로 삽입 한 이미지의 파일 이름과 비트 맵에 대한 null이 아닌 포인터로 시작하여 값으로 표시되는 값이 1 동안 유지됩니다. 어떤 점에서는 null입니다.

편집 2 :

문자열에 문자 배열을 변경하고 이렇게 검색된 파일 이름이 발견되지 않으면 더 이상지도에 추가하는 get_current_image() 고정 후, 나는를로드 할 때 나는 또한 실수를 한 것을 발견

그것은 알고 보니, 내가 지금처럼 load_images()을 작성했다

current_screen.load_images(image_loader); 

:

void MainGameScreen::load_images(ImageLoader loader) 
012 내가 처음에 질문을 게시 할 때 나는 잊었다 라인의 이미지를 포함하는

... loader에 대한 함수 호출이 실제로 전달 된 ImageLoader에 적용되지 않았 음을 의미합니다.나는 다음과 같이 바꿨다 :

void MainGameScreen::load_images(ImageLoader& loader) 

... 이제 모든 것이 잘 동작한다.

답변

1

const char *을 키로 사용한다는 것은 map이 직접 주소 비교를 수행한다는 것을 의미합니다. 즉, "문자열의 주소가 내가 메모리에 보유하고있는 문자열의 주소와 같은가요?"라는 의미입니다. 이것은 거의 확실하게 문자열 비교를 수행하는 방식이 아닙니다.

실제로이 문제의 해결책은 사용 사례에 따라 다릅니다. 첫 번째는 간단하게 const char *std::string으로 변경하는 것이 가장 간단한 솔루션이며 기본적으로 수행해야 할 작업입니다.

std::map<std::string, ALLEGRO_BITMAP*> image_map; 

그리고 광범위하게 말하자면, 당신이 문자열을 사용하고 어디 있는지, 당신도 std::string 또는 std::string const&를 사용해야합니다. 다른 것을 사용할 이유가 없습니다.

... 성능에 관심이 없다면. 그리고 게임을 작성하는 경우, 성능은 거의 확실하게 신경 쓰고 있습니다. 그러면 두 번째 해결책이됩니다. 지도에 대한 많은 조회 작업을 수행하는 것은 많은 수의 비교를 호출하는 것이므로 일반적으로 큰 문제는 아니지만 각 비교가 완전한 문자열 기반 평등 확인이기 때문에 여기에 있습니다.

해결책은, 사용자가 (또는 int64_tuint64_t 등) 이미지 문제 각 이미지의 고유 ID를로드 대신 파일명 또는 경로명의 GameImage 객체에 값들을 할당 할 때. 그런 다음 조회를 수행 할 때 해당 ID를 사용하여 조회를 수행하십시오.

귀하에게 달려 있습니다. const char *std::string으로 바꾸면 거의 확실하게 코드의 논리적 오류를 수정하고 예상대로 작동하게됩니다. 나머지는 문자열 비교를 모두 수행하면 프로그램 속도가 너무 빨라진다는 것을 발견하면 최적화 문제에 더 가깝습니다.

편집 :

새 문제가 요청한 이름을 가진 기존의 이미지를 발견하지 못할 경우 std::mapoperator[] 기능이 자동으로 (이 경우, nullptr에) 기본 값을 삽입한다는 것입니다. 당신이 원하는 코드는 더 다음과 같습니다

ALLEGRO_BITMAP * ImageLoader::get_current_image(GameImage image) 
{ 
    auto it = image_map.find(image.get_image_filename()); 
    if(it == image_map.end()) return nullptr; 
    else return it->second; 
    //return image_map[image.get_image_filename()]; 
} 

이 방법, 유효한 (NULL) 값이 해당 위치에 저장된다는 생각으로 사용하는 디버깅 도구를 속일 수 없습니다 이미지를 찾을 실패. 대신 내장 예외 기능을 사용하기를 원한다면

당신이 그것을 단순화 수 :

ALLEGRO_BITMAP * ImageLoader::get_current_image(GameImage image) 
{ 
    //Will throw an exception if nothing is found 
    return image_map.at(image.get_image_filename()); 
} 
+0

나는이 변경했지만 문제가 계속 지속됩니다. 나는 파일 이름 키가 원래 "image_map.find (image.get_image_filename()) == image_map.end()"이후 false를 반환하지만, get_current_image()를 호출 할 때의 값은 여전히 ​​null 인 것과 같다고 생각합니다. – user3726962

+1

@ user3726962 수정 된 버전의'get_current_image'를 원본 글에 추가하십시오. – Xirema

+0

키의 타입을 포함하고 있지 않기 때문에'get_current_image'를 변경하지 않았습니다 만, GameImage의 get_image_filename'은 char 배열 대신에 문자열을 반환합니다. – user3726962