창의 크기를 조정하거나 이동하는 동안 XNA가 업데이트를 일시 중지하지 못하게하려면 어떻게합니까?


15

XNA는 호출을 중지 Update하고 Draw게임 창 크기를 조정하거나 이동하는 동안.

왜? 이 행동을 막을 방법이 있습니까?

(네트워크 메시지가 펌핑되지 않기 때문에 네트워크 코드가 비 동기화됩니다.)

답변:


20

예. XNA의 내부를 약간 혼란스럽게 만듭니다. 이 비디오의 후반부에서 픽스 시연했습니다 .

배경:

이것이 발생하는 이유는 XNA Game의 기본 Form크기가 조정되거나 이벤트가 동일 할 때 게임 시계가 일시 중단되기 때문 입니다. 이것은에서 게임 루프를 구동하고 있기 때문입니다 Application.Idle. 창의 크기가 조정되면 Windows는 실행 을 막는 미친 win32 메시지 루프 작업 을 수행합니다 Idle.

따라서 Game시계를 일시 중단하지 않은 경우 크기를 조정 한 후 단일 버스트로 업데이트해야하는 시간이 엄청나게 늘어 났으므로 바람직하지 않습니다.

수정 방법 :

XNA에는 긴 이벤트 체인이 있으며 (사용하는 경우 Game사용자 지정 창에는 적용되지 않음) 기본적으로 게임 시계에 대한 기본 Form,에 SuspendResume메서드 의 크기 조정 이벤트를 연결합니다 .

이들은 비공개이므로 리플렉션사용 하여 이벤트의 후크를 해제해야합니다 (은 어디에 this있습니다 Game).

this.host.Suspend = null;
this.host.Resume = null;

필요한 주문은 다음과 같습니다.

object host = typeof(Game).GetField("host", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this);
host.GetType().BaseType.GetField("Suspend", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(host, null);
host.GetType().BaseType.GetField("Resume", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(host, null);

(어딘가에서 체인을 분리 할 수 ​​있습니다. ILSpy를 사용하여 알아낼 수 있습니다. 그러나 창 크기 조정 외에 타이머를 중단시키는 다른 것은 없습니다. 따라서 이러한 이벤트는 어느 것이나 좋습니다.)

그런 다음 XNA가에서 똑딱 거리지 않을 때 자신의 틱 소스를 제공해야합니다 Application.Idle. 나는 단순히 System.Windows.Forms.Timer:

timer = new Timer();
timer.Interval = (int)(this.TargetElapsedTime.TotalMilliseconds);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();

이제는 timer_Tick결국을 호출 Game.Tick합니다. 이제 시계가 일시 중단되지 않았으므로 XNA 고유의 타이밍 코드를 계속 사용할 수 있습니다. 쉬운! XNA의 내장 틱이 발생하지 않을 때만 수동 틱이 발생하기를 원합니다. 간단한 코드는 다음과 같습니다.

bool manualTick;
int manualTickCount = 0;
void timer_Tick(object sender, EventArgs e)
{
    if(manualTickCount > 2)
    {
        manualTick = true;
        this.Tick();
        manualTick = false;
    }

    manualTickCount++;
}

그리고 UpdateXNA가 정상적으로 작동하는 경우이 코드를 입력하여 카운터를 재설정하십시오.

if(!manualTick)
    manualTickCount = 0;

이 틱은 XNA보다 덜 정확합니다. 그러나 실시간으로 정렬되어 있어야합니다.


이 코드에는 여전히 작은 결함이 있습니다. Win32는 어리석은 못생긴 얼굴을 축복하며 마우스가 실제로 움직이기 전에 창의 제목 표시 줄을 클릭하면 본질적으로 모든 메시지를 수백 밀리 초 동안 중지 합니다 ( 동일한 링크 참조 ). 이렇게하면 Timer메시지 기반의 메시지가 표시되지 않습니다.

우리는 이제 XNA의 게임 시계를 중단하지 않기 때문에 타이머가 다시 똑딱 거리기 시작하면 많은 업데이트가 발생합니다. 그리고 슬프게도 XNA는 누적 가능한 시간을 제목 표시 줄을 클릭 할 때 Windows가 메시지를 중지하는 시간보다 약간 적은 시간으로 제한합니다. 따라서 사용자가 제목 표시 줄을 클릭하지 않고 움직이면 제목 표시 줄이 움직이지 않으면 업데이트가 많아 지고 몇 프레임이 실시간으로 떨어집니다.

(그러나 이것은 여전히 대부분의 경우에 충분 해야합니다 . XNA의 타이머는 이미 말더듬을 방지하기 위해 정확도를 희생하므로 완벽한 타이밍 이 필요한 경우 다른 작업을 수행해야합니다.)


2
좋은 종합 답변.
MichaelHouse

1
왜 정확하게 질문을 한 다음 즉시 대답합니까?
Alastair Pitts

4
공정한 질문입니다. 그것은있어 명시 적으로 권장합니다 . 질문 UI에는 "자신의 질문에 답하기"상자가 있습니다. 원래 나는 이 질문에 대한 답변을 만들려고 했지만, 그것은 오래된 답변의 편집 일뿐이며 내 솔루션은 그 질문의 일부를 해결하지 못합니다. 이렇게하면 더 나은 가시성을 얻습니다 (SO 대신 GDSE에서 XNA가 됨) 그리고 내 블로그보다는 정보가 여기에 더 적합합니다.
앤드류 러셀
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.