Вопрос
Что делать, если у вас есть 2D-игра, в которой используются действительно большие изображения (больше, чем может поддерживать ваше оборудование)? Может быть, есть какое-то интересное решение этой проблемы, которое мне никогда не приходило в голову.
Я работаю над создателем графических приключенческих игр. Моя целевая аудитория - люди, у которых практически нет опыта разработки игр (и программирования). Если бы вы работали с таким приложением, разве вы не предпочли бы, чтобы оно обрабатывало проблему внутренне, а не говорило вам «разделить ваши изображения»?
контекст
Хорошо известно, что графические карты накладывают ряд ограничений на размер текстур, которые они могут использовать. Например, при работе с XNA максимальный размер текстуры ограничен 2048 или 4096 пикселями в зависимости от выбранного профиля.
Обычно это не представляет большой проблемы в 2D играх, потому что большинство из них имеют уровни, которые могут быть построены из более мелких отдельных частей (например, плитки или преобразованных спрайтов).
Но подумайте о нескольких классических графических приключенческих играх point'n'click (например, Monkey Island). Комнаты в графических приключенческих играх обычно разрабатываются целиком, с небольшими или отсутствующими повторяемыми участками, как художник, работающий над пейзажем. Или, возможно, такая игра, как Final Fantasy 7, в которой используются большие предварительно отрендеренные фоны.
Некоторые из этих комнат могут быть довольно большими, часто занимая три или более экрана шириной. Теперь, если мы рассмотрим эти фоны в контексте современной игры высокой четкости, они легко превысят максимальный поддерживаемый размер текстуры.
Теперь очевидным решением этого является разделение фона на более мелкие участки, которые соответствуют требованиям, и их рисование рядом. Но должен ли ты (или твой художник) быть тем, кто разделяет все твои текстуры?
Если вы работаете с высокоуровневым API, разве он не должен быть готов к тому, чтобы справиться с этой ситуацией и выполнить расщепление и сборку текстур внутри себя (или в качестве предварительной обработки, такой как XNA Content Pipeline или во время выполнения)?
редактировать
Вот то, о чем я думал, с точки зрения реализации XNA.
Мой 2D движок требует только небольшого подмножества функций Texture2D. Я действительно могу уменьшить его до этого интерфейса:
public interface ITexture
{
int Height { get; }
int Width { get; }
void Draw(SpriteBatch spriteBatch, Vector2 position, Rectangle? source, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth);
}
Единственный внешний метод, который я использую, который опирается на Texture2D, это SpriteBatch.Draw (), поэтому я мог бы создать мост между ними, добавив метод расширения:
public static void Draw(this SpriteBatch spriteBatch, ITexture texture, Vector2 position, Rectangle? sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth)
{
texture.Draw(spriteBatch, position, sourceRectangle, color, rotation, origin, scale, effects, layerDepth);
}
Это позволило бы мне использовать ITexture взаимозаменяемо всякий раз, когда я использовал Texture2D раньше.
Тогда я мог бы создать две разные реализации ITexture, например RegularTexture и LargeTexture, где RegularTexture просто обернет обычный Texture2D.
С другой стороны, LargeTexture будет хранить список Texture2D, каждый из которых соответствует одному из разделенных фрагментов полного изображения. Наиболее важной частью является то, что вызов Draw () в LargeTexture должен иметь возможность применить все преобразования и нарисовать все части, как если бы они были только одним непрерывным изображением.
Наконец, чтобы сделать весь процесс прозрачным, я бы создал унифицированный класс загрузчика текстур, который будет действовать как фабричный метод. Он будет принимать путь текстуры в качестве параметра и будет возвращать ITexture, которая будет либо RegularTexture, либо LargeTexture, в зависимости от размера изображения, превышающего ограничение, или нет. Но пользователю не нужно было знать, какой это был.
Немного перебор или это звучит нормально?
Ответы:
Я думаю, что вы на правильном пути. Вы должны разделить изображения на более мелкие кусочки. Поскольку вы создаете игру, вы не можете использовать конвейер контента XNA. Если ваш производитель больше не похож на движок, который все еще будет требовать от разработчиков использовать Visual Studio. Поэтому вам нужно создать свои собственные процедуры, которые будут выполнять разбиение. Вы даже должны рассмотреть возможность потоковой передачи фрагментов до того, как они станут видимыми, чтобы вы по-прежнему не ограничивали объем видеопамяти игроков.
Есть несколько трюков, которые вы можете сделать специально для приключенческих игр. Я думаю, что, как и во всех классических приключенческих играх, у вас будет несколько слоев этих текстур, чтобы ... ваш персонаж мог ходить за деревом или зданием ...
Если вы хотите, чтобы эти слои имели эффект паралаксинга, тогда, когда вы разделяете свои плитки, просто пропустите все полупрозрачные один раз. Здесь нужно подумать о размере плитки. Меньшие плитки добавят управление накладными расходами и вызовами отрисовки, но будут меньше данных, когда большие плитки будут более дружественными к графическому процессору, но будут иметь большую прозрачность.
Если у вас нет эффекта паралаксинга, тогда вместо того, чтобы покрывать всю сцену 2-4 гигантскими изображениями с глубиной 32 бита, вы можете создать только одну 32-битную глубину. И у вас может быть слой трафарета или глубины, который будет только 8 бит на пиксель.
Я знаю, что это не похоже на управление активами сторонними разработчиками, но на самом деле это не обязательно. Например, если у вас есть улица с 3 деревьями, и игрок идет за 2 из них, перед третьим деревом и остальным фоном ... Просто сделайте макет сцены так, как вы хотите в редакторе, а затем в сделав шаг от своего создателя игры, вы можете испечь эти гигантские изображения (ну, маленькие плитки большого изображения).
О том, как классические игры делали это. Я не уверен, что они, вероятно, делали одинаковые трюки, но вы должны помнить, что в то время, когда экран был 320х240, игры были с 16 цветами, что при использовании палатализированных текстур позволяет кодировать 2 пикселя в одном байте. Но это не так, как нынешние архитектуры работают так: D
Удачи
источник
Разрежьте их, чтобы они больше не были сколь угодно большими, как вы говорите. Там нет магии. Те старые 2D-игры либо делали это, либо воспроизводились в программном обеспечении, и в этом случае аппаратные ограничения не превышали объем оперативной памяти. Следует отметить, что многие из этих 2D-игр на самом деле не имели огромного фона, они просто медленно прокручивались, чтобы чувствовать себя огромными.
Что вы хотите сделать в своем создателе графических приключенческих игр, так это предварительно обработать эти большие изображения во время какого-то этапа «сборки» или «интеграции» перед тем, как игра будет упакована для запуска.
Если вы хотите использовать существующий API и библиотеку вместо того, чтобы писать свой собственный, я бы посоветовал вам конвертировать эти большие изображения в плитки во время этой «сборки» и использовать механизм 2D-плиток, которых много.
Если вы хотите использовать свои собственные 3D-методы, вы все равно можете разделить их на фрагменты и использовать хорошо известный и хорошо спроектированный 2D-API, чтобы написать для этого свою собственную 3D-библиотеку, таким образом вы гарантированно начнете с хороший дизайн API и меньше дизайна требуется с вашей стороны.
источник
Если вы знакомы с тем, как выглядит квадри в визуальной практике, я использовал метод, который разрезает детализированные большие изображения на меньшие, относительно похожие на то, как выглядит доказательство / визуализация квадродерева. Тем не менее, мои были сделаны таким образом, чтобы вырезать области, которые могут быть закодированы или сжаты по-разному в зависимости от цвета. Вы можете использовать этот метод и делать то, что я описал, поскольку это также полезно.
Во время выполнения их обрезка временно потребует больше памяти и замедлит время загрузки. Хотя я бы сказал, что это зависит от того, заботитесь ли вы больше о физической памяти или времени загрузки пользовательской игры, созданной вашим редактором.
Время загрузки / прогона: способ загрузки - просто разрезать ее на части пропорционального размера. Если учитывать нечетное количество пикселей, учитывайте один пиксель справа, никому не нравится, когда его изображения обрезают, особенно неопытным пользователям, которые могут просто не знать, что это не совсем их дело. Сделайте их наполовину ширины ИЛИ наполовину высоты (или 3-х, 4-х и т. Д.), Причина не в квадратах или 4-х секциях (2 строки 2 столбца) в том, что это уменьшит размер мозаичной памяти, поскольку вы не будете беспокоиться о x и y в то же время (и в зависимости от того, сколько изображений такого размера, это может быть очень важно)
До руки / автоматически: в этом случае мне нравится идея предоставить пользователю возможность сохранить его в одном изображении или сохранить в виде отдельных фрагментов (одно изображение должно быть по умолчанию). Сохранение изображения в формате .gif будет работать отлично. Изображение будет в одном файле, и вместо того, чтобы каждый кадр был анимацией, он был бы больше похож на сжатый архив одного и того же изображения (что, по сути, в любом случае представляет собой .gif). Это позволило бы упростить физическую передачу файлов, облегчить загрузку:
Да, и если вы используете метод .gif, вы должны изменить расширение файла на что-то другое (.gif -> .kittens) ради меньшей путаницы, когда ваш .gif анимирует, как будто это поврежденный файл. (не беспокойтесь о законности этого, .gif это открытый формат)
источник
Это будет звучать очевидно, но почему бы просто не разделить вашу комнату на более мелкие части? Выберите произвольный размер, который не столкнется с любыми видеокартами (например, 1024x1024 или больше), и просто разбейте свои комнаты на несколько частей.
Я знаю, что это позволяет избежать проблемы, и, честно говоря, это очень интересная проблема для решения. В любом случае, это своего рода тривиальное решение, которое может работать для вас время от времени.
источник