2010-11-20 3 views
6

게임 내 메뉴의 경우 화면에 한 번만 그립니다. 그런 다음 더러운 것으로 판단되면 다시 그립니다. 이것은 사용자가 다시 그리기를 유발해야하는 작업을 수행 할 때마다 true로 설정된 부울을 통해 처리 된 다음 그리기 루프는 메뉴를 그리기 전에 해당 값을 검사합니다. 이 논리는 3.1에서 완벽하게 작동했지만 4.0에서는 메뉴가 깜박이며 (1 프레임에 그려짐) 다시 그리기 전까지 자주색 화면이 표시됩니다.XNA 3.1에서 4.0은 상수 다시 그리기가 필요하거나 자주색 화면을 표시합니다

아래의 문제를 보여주기 위해 4.0에서 매우 간단한 테스트 게임을 만들었습니다. 화면이 자주색으로 보입니다. 줄 설정 _isDirty를 false로 제거하면 수레 국화가 파란색 배경으로 표시됩니다.

public class Game1 : Microsoft.Xna.Framework.Game 
{ 
    GraphicsDeviceManager graphics; 
    bool _isDirty = true; 

    public Game1() 
    { 
     graphics = new GraphicsDeviceManager(this); 
    } 
    protected override void Draw(GameTime gameTime) 
    { 
     if (_isDirty) 
     { 
      GraphicsDevice.Clear(Color.CornflowerBlue); 
      _isDirty = false; 
     } 
     base.Draw(gameTime); 
    } 
} 

어떻게하면 XNA 3.1에서 동작을 얻을 수 있습니까? 여러 사람들이 PreserveContents에 대해 언급 한 것을 보았습니다.하지만 잘못 적용하지 않는 한 4.0에서는 효과가없는 것 같습니다.

Update 
BeginDraw 
Draw 
EndDraw 

EndDraw의 기본 구현은 궁극적으로 GraphicsDevice.Present를 호출

답변

13

은 여기 XNA 게임에서 호출되는 것을의 대략적인 개요입니다. 이중 버퍼링이 켜지면 뒤 버퍼와 앞 버퍼를 서로 바꿉니다.

그래서 무슨 일이 일어나고있는 것입니다 : 주위

  • 처음 : 당신이 백 버퍼에 장면을 그리기하고 앞으로 XNA 스왑을시키는 것입니다.

  • 둘째 시간 : DirectX에서 이러한 표면을 초기화하는 보라색으로 채워진 채 아무 것도 드로잉하지 않고 그 뒤를 앞에 긋습니다!

  • 그 다음 시간 : 아무 것도 그리지 않으므로 두 표면 사이에 화면 깜박임이 표시됩니다.

XNA에서 그리기를 억제하는 데는 여러 가지 방법이 있습니다. 나는 그들에게 this answer to a similar question로 간다. 그 대답에, 나는 당신과 같이, BeginDraw를 오버라이드 (override) 추천 :

BeginDraw false를 반환, DrawEndDraw (그래서 Present)이 그 프레임을 호출되지 않습니다
protected override bool BeginDraw() 
{ 
    if(_isDirty) 
     return base.BeginDraw(); 
    else 
     return false; 
} 

. 그리고 아무 것도 그려지지 않을 것이고 프런트/백 버퍼는 바뀌지 않을 것이다.

+1

Perfect! Draw의 내부 동작을 자세히 설명하는 시간을내어 주셔서 감사합니다. –

+0

참고 : [여기에서] (http://stackoverflow.com/a/16910684/165500)를 발견 했으므로 XNA는 'Present'중에 실제로 초기화되지 않은 버퍼 (진한 보라색으로 지워짐)를 적극적으로 표시하므로, 깜박임에 대한 나의 대답은 잘못되었습니다. 해결책은 여전히 ​​동일하지만. (펜티의 [대답] (http://stackoverflow.com/a/6283242/165500) 여기에 메커니즘에 대한 자세한 내용이 있지만, 나는 그것을 쇠망아지와 반사 시켜서는 안된다. 적절한 API를 사용하는 것이 훨씬 현명하다. , 내 대답 당) –

+0

"_isDirty '_isDirty'이름이 현재 컨텍스트에 존재하지 않습니다. '라는 오류가 발생합니다. XNA 4.0 사용하고이 메서드는 Game1 클래스에 넣습니다. 어떤 아이디어? – Xonatron

2

최근에 나는 이것도 발견했습니다. 나는 버퍼를 뒤집는 것이 문제라고 생각하지 않는다. 그것은 3.1과 4.0에서 동일해야합니다. 나는 GraphicsDevice를 ILSpy로보고 다음을 발견했다 :

변경된 점은 private 플래그가 설정된 경우 현재 렌더링 대상이 GraphicsDevice.Present()에서 처음 지워진다는 점입니다. 기본적으로이 플래그는 처음에 설정됩니다 (렌더링 타겟은 깨끗합니다). 렌더 타겟에 드로잉하면이 플래그가 지워집니다 (렌더링 타겟이 더러워졌습니다). GraphicsDevice.Present()는 의무를 수행 한 후 다시 플래그를 설정합니다 (렌더링 타겟이 창에 플러시되고 다시 깨끗하게 처리됨).

GraphicsDevice.Present()에서 결과를 얻으려면 엄격한 순서로 Draw() 및 EndDraw()를 호출해야합니다.

이전에 Draw()를 호출하지 않고 EndDraw()를 호출하면 렌더링 대상의 내용을 가져 오지 않고 (지워짐) 대신 자주색 화면 만 가져옵니다.

불행히도, 깃발은 비공개이며 얻을 수있는 확실한 방법이 없습니다. 리플렉션을 사용하면 다음과 같이 플래그를 지우고 아무 것도 그리지 않고 렌더링 타겟을 더럽게 만듭니다. , 0);

장소 EndDraw()로 호출하기 전에 위의 라인 (GraphicsDevice에 현재있는 GraphicsDevice 인스턴스), 그리고 행동이 내 특정 경우

+0

또 다른 방법으로, 현재 사용중인 화면 버퍼의 내용을 매번 사용할 새 버퍼로 복사 할 수 있습니까? – Xonatron

0

3.1에서 사용했던갑니다, 내가 가지고 그리기를 담당하는 상태를 전환하는 상태 머신입니다. 따라서 두 게임 상태 사이를 전환하면 그릴 내용이 없으며 다음 게임 상태가 활성화 될 때까지 화면이 자주색으로 깜박입니다.

내가 해결하기 위해 한 것은 업데이트 상태에서 게임 개체에 SuppressDraw() 메서드를 호출하는 것입니다. 그러면 다음 업데이트가 수행 될 때까지 그리기 작업이 수행되지 않습니다.

isDirty 플래그를 설정할 때를 제외하고 항상 Update에서 항상 호출하는 것을 막을 수있는 방법은 없다고 생각합니다. 그러나 화면이 파손될 수있는 다른 이벤트/사례를 처리 할 준비가되어 있어야합니다.

관련 문제