XNA 3.1 до 4.0 требует постоянного перерисования или отобразит фиолетовый экран
Вопрос
Для меню в моей игре я рисую их один раз на экран, а затем только перерисовал, если они считаются грязными. Это обрабатывается через логическое значение для true, всякий раз, когда пользователь выполняет действие, которое должно вызывать перерисование, а затем цикл для вытягивания проверит это значение, прежде чем рисовать меню. Эта логика отлично работала в 3.1, но в 4.0 меню будет мерцать (нарисовано для 1 рамы), затем показать фиолетовый экран, пока снова нарисован.
Я создал очень простую тестовую игру в 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? Я видел несколько людей, упомянувших серверы, но это не имеет никакого эффекта в 4.0, если я не применяю его неправильно.
Решение
Вот грубый обзор того, что называется в ггной игре:
Update
BeginDraw
Draw
EndDraw
Реализация по умолчанию EndDraw
в конечном итоге звонит GraphicsDevice.Present
. Отказ С включенной двойной буферией это сводится к спине и передние буферы.
Так что происходит:
Первый раз вокруг: вы рисуете вашу сцену к задним буфере, а затем отпустить XNA на передней.
Второй раз вокруг: вы ничего не рисовали, оставив поверхность, наполненную фиолетовым цветом, который DirectX инициализирует эти поверхности, и замена это спереди!
Последующие времена: вы ничего не рисуете, поэтому вы увидите мерцание дисплея между этими двумя поверхностями.
Существует несколько способов подавления рисунка в XNA. Я иду над ними в Этот ответ на аналогичный вопрос. Отказ Как и в этом ответе, я рекомендую переопределить Begindraw, как так:
protected override bool BeginDraw()
{
if(_isDirty)
return base.BeginDraw();
else
return false;
}
Когда BeginDraw
Возвращает false, Draw
а также EndDraw
(и так Present
) не будет называться этой рамкой. Ничто не будет рисовать, а буферы фронта / задней части не поменяются.
Другие советы
Я недавно наткнулся на это тоже; Я не думаю, что это проблема с листыми буферами. Это должно быть то же самое в 3.1 и 4.0. Я посмотрел на GraphicsDevice с Ilspy и узнал это:
То, что изменилось, в том, что в 4.0 текущая цель рендеринга сначала очищается в GraphicateDevice.present (), если установлен личный флаг. По умолчанию этот флаг будет установлен изначально (рендеринг цели чисто). Рисунок в цель рендеринга очищает этот флаг (рендеринг цели сейчас грязно). После выполнения дежурства, GraphicsDevice.present () снова устанавливает флаг (рендеринг цели был «покрасен» к вашему окну и теперь снова считается чистым).
Чтобы получить результаты от GraphicsDevice.present (), вам нужно позвонить на рисовать () и enddraw () в строгой последовательности.
Если вы вызываете EndDraw () без предварительного вызова, чтобы нарисовать (), вы не получите содержимое цели рендеринга (что устанавливается), вместо этого можно получить только фиолетовый экран.
К сожалению, флаг является частным, и нет чистого способа добраться до него. Вы можете использовать отражение для очистки такого такого флага, принудительно принуждение целевой целевой цели, не рисуя ничего в нее:
GraphicsDevice.gettype (). Getfield («LazyclearFlags», BindingFlags.nonpublic | BindingFlags.Instance) .stebalue (GraphicsDevice, 0);
(GraphicsDevice - ваш текущий экземпляр графических данных)
Поместите вышеуказанную линию перед вызовом в EndDraw (), и поведение возвращается к тому, что было в 3.1
В моем конкретном случае у меня есть государственная машина, которая переключается между состояниями, которые несут ответственность за рисунок. Поэтому, когда я перехожу между двумя игровыми состояниями, нечего рисовать, и экран мигает фиолетовым, пока не будет активно следующее игровое состояние.
Что я сделал, чтобы решить, что это было просто, в обновлении, если у меня нет состояния, позвоните SupressDraw () Метод в игровом объекте. Это предотвращает проведение рисунка до тех пор, пока не произойдет следующее обновление.
Я полагаю, что нет ничего останавливать вас от того, что вы всегда называете его в обновлении, за исключением случаев, когда вы устанавливаете флаг ISDIRTY. Но вы должны были быть готовы обрабатывать другие события / случаи, когда экран может быть разбитым.