다시 시작하지 않고 옵션 화면에서 디스플레이 설정을 업데이트하려면 어떻게합니까?


9

현재 Allegro 5와 함께 C ++ 11에서 2D RPG를 만들고 있습니다.

내 목표는 옵션 메뉴에서 옵션이 변경 될 때 게임 설정을 어떻게 든 업데이트하는 것입니다. 사용자가 게임을 다시 시작하도록하고 싶지 않습니다. 해상도를 변경하거나 전체 화면에서 창으로 전환 할 때 다른 게임을 다시 시작할 필요가 없으므로 내 게임도 마찬가지입니다. 아래 시스템의 단순화 된 모습을 참조하십시오.

옵션 화면에서 게임 오브젝트를 직접 호출하고 싶지는 않습니다. 점선은 단지 내가 달성하려는 효과를 설명하기위한 것입니다. 시스템의 다른 부분에서 옵션이 변경 될 때 게임이 업데이트되는 원인이됩니다.

상해

ScreenManager에는 GameScreen현재 존재 하는 모든 객체 의 목록이 있습니다 . 팝업을 포함하여 게임에서 다양한 화면이 표시됩니다. 이 디자인은 C # / XNA게임 상태 관리 샘플을 다소 준수합니다 .

ScreenManager제에 대한 참조 포함 Game개체를. Game개체 초기화하고 수정 게임의 설정. 해상도를 변경하려면 전체 화면으로 이동하거나 Game클래스 에서 볼륨을 음소거하십시오 .

그러나 OptionsScreen은 현재 Game 클래스에 액세스 할 수 없습니다. 아래 다이어그램을 참조하십시오.

게임 화면은 onFinished, onTransitionStart및의 세 가지 이벤트를 신호 할 수 있습니다 onTransitionEnd. onOptionsChanged하나의 화면 만 수행하기 때문에 없습니다 . ScreenManager는 모든 화면을 GameScreens 로 처리하므로 이벤트 처리를 설정할 수 없습니다 .

내 질문은 OptionsMenu의 변경 사항을 다시 시작하지 않아도 즉시 변경되도록 디자인을 어떻게 변경할 수 있습니까? Game적용 버튼을 클릭하면 객체 업데이트를 요청하는 것이 좋습니다 .


이 질문 (게임과 관련이 있음에도 불구하고)은 실제 게임보다는 일반적인 OO 디자인에 관한 것이기 때문에 programmers.stackexchange.com에 완벽하게 맞는 것 같습니다
bughi

이렇게 멋진 그래프를 어디서 얻었습니까?
joltmode

@psycketom : 첫 번째는 Visio 2013에서, 두 번째는 VS2012에서 코드로 생성합니다. 희망이 도움이됩니다!
IAE

답변:


1

내가 본 것 중 가장 쉬운 방법은 시작시 옵션 파일을 읽어 현재 디스플레이 설정을 확인하는 것입니다. 그런 다음 옵션 화면이 표시되면 파일에서 모든 현재 옵션을로드하십시오.

apply또는 ok버튼을 통해 변경 사항을 완료 하면 파일에 다시 저장됩니다. 변경 사항이 디스플레이에 영향을 미치는 경우, 게임을 다시 시작해야 변경 사항이 적용되도록 사용자에게 알립니다.

게임이 다시 시작되면 파일에서 (현재 새로운) 디스플레이 설정을 다시 읽습니다.

--편집하다--

Annd ... 마지막 문장을 발견하면 도움이되었을 것입니다. 다시 시작하지 않아도됩니다. 구현 및 백엔드 그래픽 라이브러리에 따라 상황을 조금 더 어렵게 만듭니다.

IIRC, Allegro에는 디스플레이 설정을 즉시 변경할 수있는 기능 호출이 있습니다. 나는 아직 Allegro 5를 시작하지 않았지만 4에서 할 수 있다는 것을 알고 있습니다.


문제가 Allegro 및 그 기능과 관련이 있다고 생각하지 않습니다. "제 질문은 OptionsMenu의 변경을 다시 시작하지 않아도 즉시 변경되도록 디자인을 어떻게 변경할 수 있습니까?" "옵션 화면은 현재 게임 클래스에 액세스 할 수 없기 때문에"다시 시작하기 때문에 올바르게 이해하면 설정 파일에서로드해야합니다.
ClassicThunder

@Casey : 안녕하세요 케이시! :) 예, 구성 파일을 사용하여 관련 디스플레이 데이터를 저장하고 있지만 재시작을 피하고 싶습니다. 작은 게임이므로 다른 게임을 다시 시작하지 않고도 해상도를 변경할 수 있으므로 사용자가 내 컴퓨터를 다시 시작해야하는 이유를 알 수 없습니다. 유용성 문제입니다. allegro dispay 함수를 호출 할 수는 있지만, OOP를 유지하려고 노력하고 있습니다. 나는 그 좋은 디자인을 고려하지 않습니다.
IAE

"다시 시작하지 않고"비트를 강조 표시하여 다른 사람들이 같은 마지막 문장에서 넘어지지 않도록했습니다. 그런 중요한 사실이 끝나지 말아야한다고 사과드립니다.) :
IAE

@SoulBeaver 누가는 말한다 있어야 당신이 다시 시작하지 않도록 그것을 만들? 실제로는 오늘날 점점 일반화 되고 있습니다 . 대규모 예산 게임의 일부 최신 릴리스 (XCOM : Enemy Unknown, Skyrim 등)를 다시 시작해야합니다. (Steam에 있다는 사실은 서버 측 옵션 동기화로 인해 범인 ​​일 수 있지만 거기에 가지 않겠습니다 ...)
Casey

1
@Casey : True, 특정 옵션의 경우 왜 이것이 필요한지 알 수 있지만 전체 화면 / 창 또는 화면 해상도와 같은 이유는 무엇입니까? 이러한 설정을 다시 시작해야하는 게임은 본 적이 없습니다. 기본 질문은 : 게임에서 설정을 자동으로 변경할 수있을 때 사용자를 강제로 다시 시작해야하는 이유는 무엇입니까?
IAE

1

이것이 제가 게임을 위해하는 일입니다. 물건을 초기화하기위한 'init'와 'reset'의 두 가지 별도 기능이 있습니다. Init은 시작시 한 번만 호출되며 기본 자산로드와 같은 설정에 의존하지 않는 작업을 수행합니다. Reset은 화면 해상도에 따라 UI를 배치하는 것과 같은 작업을 수행하므로 설정이 변경 될 때마다 호출됩니다.

init();
bool quit = false;
while( !quit )
{
    createWindow();
    reset();

    bool settings_changed = false;
    while( !quit && !settings_changed )
    {
        ... main loop
        // set quit=true if user clicks 'quit' in main menu
        // set settings_changed=true if user clicks 'apply' in options
    }

    destroyCurrentWindow();
}

나는 Allegro에 익숙하지 않지만 내 대답은 매우 일반적이므로 비슷한 문제가있는 사람이나 다른 사람에게 도움이되기를 바랍니다.


흥미로운 해결책입니다. 재설정이 호출 될 때마다 엄격하게 제어하려고했지만 변경에 관계없이 수행합니다. 그것은 확실히 구현할 수있는 것입니다. 감사합니다.
IAE

1

현재 아키텍처를 어지럽히 지 않으면 서 두 가지 방법이 있습니다. 먼저 클래스 의 Game인스턴스에 대한 포인터를 저장할 수 있습니다 OptionsScreen. 둘째, Game클래스는 주어진 간격, 즉 매 초마다 현재 설정을 가져올 수 있습니다.

실제로 새로운 설정에 적응하기 위해 Game클래스는 현재 설정을 가져오고이를 기반으로 다시 초기화하는 일종의 재설정 기능을 구현해야합니다.

깨끗한 솔루션을 위해서는 일종의 글로벌 관리자가 필요하므로 구현하는 것이 더 많은 노력입니다. 예를 들어 이벤트 시스템 또는 메시징 시스템. 집계 나 구성 등과 같은 강력한 바인딩없이 클래스가 통신하도록하는 것이 매우 유용합니다.

글로벌 이벤트 관리자를 사용하면 이전에 청취하도록 등록 된 OptionsScreen다시 그리기 이벤트를 전체적으로 발생시킬 수 Game있습니다.

일반적으로 이벤트 및 콜백을 청취하는 이벤트를 저장하는 관리자 클래스를 해시 맵에서 구현할 수 있습니다. 그런 다음 해당 관리자의 단일 인스턴스를 작성하고 포인터를 컴포넌트에 전달할 수 있습니다. 최신 C ++을 사용 std::unordered_map하면 해시 맵으로 사용 하고 std::function콜백을 저장할 수 있으므로 매우 쉽습니다 . 키로 사용할 수있는 방법에는 여러 가지가 있습니다. 예를 들어, 이벤트 관리자 문자열을 기반으로 구성 요소를보다 독립적으로 만들 수 있습니다. 이 경우 std::string해시 맵에서 키로 사용 합니다. 나는 개인적으로 이것을 좋아하고 성능 문제는 없지만, 대부분의 전통적인 이벤트 시스템은 이벤트를 클래스로 사용합니다.


다니엘 안녕하세요. 이미 boost :: signals를 사용하여 기본적인 이벤트 처리 체계를 설정하고 있습니다. 게임 스크린에서 스크린 매니저까지의 강점은 실제로 이벤트 처리입니다. 글로벌 이벤트 관리자의 아키텍처를 자세히 설명하는 자료가 있습니까? 더 많은 작업이든 아니든간에 이것은 깨끗한 구현으로 이어질 수있는 것처럼 들립니다.
IAE

나는 이것에 대한 연구를 읽지 못했지만 내 작은 엔진을 위해 글로벌 이벤트 이벤트 관리자를 구현했습니다. 구현에 관심이 있으시면 링크를 보내 드리겠습니다. 자세한 내용을 다루기 위해 답변을 업데이트했습니다.
danijar

1

음, 이것은 관찰자 패턴의 특정한 경우입니다.

콜백과 관련된 솔루션이 있습니다. 느슨한 커플 링을 원할 경우이 작업을 수행하는 가장 좋은 방법이며 가장 깨끗한 방법이라고 생각합니다. 글로벌 관리자 나 싱글 톤은 포함되지 않습니다.

기본적으로 일종의이 있어야합니다 SettingsStore. 거기에 설정이 저장됩니다. 새 화면을 만들 때 상점에 대한 포인터가 필요합니다. 이 경우 OptionsScreen일부 설정 값 자체가 수정됩니다. 이 경우 GameScreen그냥 읽을 것입니다. 따라서 게임에서 하나의 인스턴스 만 만들면 인스턴스가 필요한 모든 화면에 전달됩니다.

이제 해당 SettingsStore클래스는의 목록을 갖습니다 notifiables. 그것들은 특정 ISettingChanged인터페이스 를 구현하는 클래스입니다 . 인터페이스는 다음 방법을 포함하는 간단한 인터페이스입니다.

void settingChanged(std::string setting);

그런 다음 화면에서 관심있는 각 설정에 대한 논리를 구현합니다. 그런 다음 알림을 받으려면 상점에 자신을 추가하십시오 store->notifyOnChange(this);. 설정이 변경되면 설정 이름으로 콜백이 호출됩니다. 그런 다음에서 새로운 설정 값을 검색 할 수 있습니다 SettingsStore.

이제 다음 아이디어를 통해 추가 기능을 보강 할 수 있습니다.

  • 설정 문자열을 저장하는 클래스를 사용하십시오- SettingsStore복사 붙여 넣기 문자열을 방지하기 위해 (const 문자열) 일 수도 있습니다 .
  • 더 좋은 방법은 문자열 대신 열거 형을 사용하여 설정을 지정하는 것입니다.
  • 콜백에서 이전 값과 새 값을 인수로 지정할 수도 있지만 string 또는 int 값 또는 기타 값을 가질 수 있기 때문에 더 복잡합니다. 그것은 당신에게 달려 있습니다.

0

파일에서 변수로 설정을 읽습니다. 화면 관리자가 방금 온 화면이 옵션 화면인지 추적 한 다음 변수 인 경우 설정을 다시로드하십시오. 사용자가 게임을 종료하면 변수의 설정을 파일에 다시 씁니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.