Я C++
и DirectX
программист-любитель, поэтому большая часть знаний, которые у меня есть, взяты из старых книг по разработке игр, в которых дизайн кода предназначен только для того, чтобы что-то запустить и запустить в качестве демонстрации, оставляя мне множество соображений по дизайну даже для самая простая из программ. Во время разработки такой программы я недавно узнал о RAII
, поэтому я решил попробовать этот шаблон проектирования, потому что, как я понял, объект должен быть пригодным для использования и действительным при создании, и это значительно упрощает способ использования объектов. программа. Раньше я использовал шаблон create()
и destroy()
в некоторых своих объектах, что приводило к большому количеству проверок в большинстве функций-членов.
В архитектуре программы у меня очень мало графических объектов, являющихся обертками вокруг DirectX
ресурсов, один из которых является Texture
объектом. Например, если я хочу визуализировать тайловую карту, у меня может быть Tile
объектов, созданных с помощью указателей на AnimatedImage
объектов, которые созданы с указателями на Texture
объектов.
Проблема с использованием DirectX
заключается в том, что бывают случаи, когда графическое устройство теряется, например, при обновлении драйвера видеокарты во время выполнения программы. Когда происходят такие события, существующие графические ресурсы должны быть высвобождены и повторно получены для продолжения рендеринга в обычном режиме, включая уничтожение и реконструкцию объектов Texture
. Из-за этого использование шаблона проектирования RAII
может показаться не лучшим выбором. Мне нужно будет воссоздать объекты Texture
, воссоздать объекты AnimatedImage
, а затем воссоздать объекты Tile
. Это кажется чрезвычайно хлопотным, потому что некоторые объекты, которые воссоздаются, будут содержать больше, чем просто данные изображения.
Итак, если мы начнем с примера кода (не точного, но своего назначения он выполняет):
// Construct graphics objects into some structure we will pass around.
graphics.pDevice = new GraphicsDevice(windowHandle, screenWitdth, screenHeight);
graphics.pTexture1 = new Texture(graphics.pDevice, width1, height1, pPixelData1);
graphics.pTexture2 = new Texture(graphics.pDevice, width2, height2, pPixelData2);
graphics.pSpriteBuffer = new SpriteBuffer(graphics.pDevice, maxSprites);
В другом месте программы, которая создает объекты для тайловой карты:
// Construct some in-game animations.
images.pGrass = new AnimatedImage(graphics.pTexture1, coordinates1[4], duration1);
images.pWater = new AnimatedImage(graphics.pTexture2, coordinates2[4], duration2);
// Construct objects to display the animation and contain physical attributes.
thisMap.pMeadowTile = new Tile(images.pGrass, TILE_ATTRIBUTE_SOFT);
thisMap.pPondTile = new Tile(images.pWater, TILE_ATTRIBUTE_SWIMMABLE);
Затем во время процедуры рендеринга:
while (gameState.isRunning())
{
graphics.pSpriteBuffer->clear();
thisMap.bufferSprites(graphics.pSpriteBuffer);
graphics.pSpriteBuffer->draw();
if (graphics.pDevice->present() == RESULT_COULD_NOT_COMPLETE)
{
// Uh oh! The device has been lost!
// We need to release and recreate all graphics objects or we cannot render.
// Let's destruct the sprite buffer, textures, and graphics device.
// But wait, our animations were constructed with textures, the pointers are
// no longer valid and must be destructed.
// Come to think of it, the tiles were created with animations, so they too
// must be destructed, which is a hassle since their physical attributes
// really are unrelated to the graphics.
// Oh no, what other objects have graphical dependencies must we consider?
}
}
Есть ли какая-то концепция дизайна, которую я здесь упускаю, или это один из тех случаев, когда RAII
работает, но с неоправданно большими затратами, если существует много зависимостей между объектами? Существуют ли какие-либо известные шаблоны проектирования, которые специально подходят для этого сценария?
Вот некоторые из способов, которыми я думал о подходе к этому:
Оснастите графические объекты методом
recreate()
. Преимущество состоит в том, что любой объект, указывающий на текстуру, может сохранить этот указатель без уничтожения. Недостатком является то, что если повторное получение не удастся, я останусь с объектом-зомби, который ничем не лучше шаблонаcreate()
иdestroy()
.Добавьте уровень косвенности, используя реестр всех графических объектов, который будет возвращать индекс для указателя
Texture
или указатель для указателяTexture
, чтобы существующие объекты, которые зависят от графики, не нужно было уничтожать. Преимущества и недостатки такие же, как и выше, с дополнительным недостатком дополнительных накладных расходов из-за косвенности.Сохраните текущее состояние программы и отмотайте назад до тех пор, пока графические объекты не будут повторно получены, затем перестройте программу в том состоянии, в котором она была. Никакого реального преимущества я не могу придумать, но кажется наиболее
RAII
подходящим. Недостатком является сложность реализации этого для сценария, который не слишком распространен.Полностью отделите все визуальные представления объектов от их физических представлений. Преимущество состоит в том, что на самом деле создаются только те объекты, которые необходимо воссоздать, что может оставить остальную часть программы в допустимом состоянии. Недостатком является то, что физическим и визуальным объектам по-прежнему необходимо каким-то образом знать друг о друге, что может привести к некоторому раздуванию кода управления объектами.
Прервать выполнение программы. Преимущество в том, что это настолько просто, насколько это возможно, и очень мало работы тратится на то, что не часто случается. Недостатком является то, что это будет неприятно для любого, кто использует программу.