Использование Paint в качестве редактора уровней

Всю сознательную программистскую деятельность я увлекался созданием игр и не любил делать редакторы и прочие утилиты. Главным моим редактором почти всегда был Paint. Но для игр, в которых уровень статичен и состоит из тайлов (Марио подобные и прочие танчики), это более-менее оправдано, т.к. одному пикселю из файла уровня, созданного в Paint, соответствует тайл в игре. А что если требуется создать игру, где нет тайлов, а игровая локация состоит из неровных скалистых пещер. Или игру, в которой много движущихся элементов (летающие платформы, лифты, циркулярные пилы, вращающиеся по окружности).

Создавать редактор для таких целей мне по-прежнему не хотелось. О том, как я это решил с помощью Paint опишу в этой статье.

Я не буду приводить названия игр и давать ссылки на них, потому что это не демонстрация и не реклама игр, а описание метода, который в них применяется.

Неровная карта

Первая игра не блещет разнообразием геймплея: играем за некий подводный кораблик, двигающийся с помощью реактивного двигателя, и уворачиваемся от скал и прочих врагов:

Извиняюсь за качество видео, снимали на телефон

По видео видно, что локация состоит из земли (которой касаться нельзя), бекграунда, воды, крутящихся ежиков (враги) и эмиттеров, выпускающих эти ежики. Да, еще там есть рыбки и водоросли, но они генерируются случайным образом и не имеют отношения к файлу уровня.

Уровень из видео показан слева (увеличено в 4 раза):

В левом верхнем углу можно заметить зеленый пиксель, так отмечается стартовая позиция, следует запомнить это место, т.к. все последующие иллюстрации будут демонстрировать именно его.

Файл уровня состоит из 3-х слоев:
  • Слой объектов, с которыми игрок взаимодействует: земля, эмиттеры и ежики, а также стартовая позиция и выход. Ориентация эмиттеров (могут стрелять в одном из четырех направлений) не задается, она вычисляется при загрузке, исходя из соседних «земельных» пикселей
  • Слой воды (это аркада, поэтому закон сообщающихся сосудов здесь не действует)
  • Слой с бекграундом

Вода пересекается с землей, бекграунд пересекается с землей и водой, поэтому они разделены на 3 слоя. Размер персонажа вдвое меньше размера пикселя в файле карты.

Если это сейчас просто так взять и отрендерить (потайлово), то локация будет состоять из гигантских квадратов. Да и количество таких тайлов достаточно велико (61х69 для этой карты). Поэтому был применён другой способ рендеринга (нетайловый), при котором можно отобразить карту за один вызов (на самом деле за три: отдельно воду, бекграунд и финальная склейка). Это благодаря тому, что весь уровень помещается в одну единственную текстуру, назовём её tex_level. И натягивается она на полноэкранный квад (полигон, размером с экран). Перед этим выставляются текстурные координаты в зависимости от виртуальной камеры, которая привязана к персонажу.

Слева – примерно так выглядит текстура tex_level и охват виртуальной камеры. Справа – назначенные текстурные координаты для полноэкранного квада, т. о. на экран попадает кусочек текстуры tex_level.

Вначале текстуру tex_level надо подготовить. Для этого заведём массив под пиксели этой текстуры:
unsigned int pix[w*h];

где w – ширина файла с уровнем, h – высота, деленная на 3 (т.к. три слоя).

Теперь в цикле считываем каждый пиксель исходной карты из каждого слоя и в зависимости от цвета (он же и тип тайла) заполняем соответствующие цветовые каналы в пикселе pix, а именно:

for(int i=0;i<w*h;i++)				//цикл для всех пикселей
{
	int c=GetPixel(i%w,i/w);			//получить цвет из 1-го слоя
	if(c==RGB(0,0,0)) pix[i]=0xff;		//для черного цвета – это земля (R канал)
	c=GetPixel(i%w,i/w+h);			//получить цвет из 2-го слоя
	if(c==RGB(0,0,255)) pix[i]|=0xff0000;	//синий цвет – вода (B канал)
	c=GetPixel(i%w,i/w+h+h);			//получить цвет из 3-го слоя
	if(c==RGB(127,127,127)) pix[i]|=0xff00;	//серый цвет – бекграунд (G канал)
}

Техническая особенность: на самом деле w и h равны ближайшей в сторону увеличения степени двойки для ширины и высоты карты, недостающие пиксели замащиваются красным цветом (земля), а этот цикл можно считать псевдокодом.

Видно, что один и тот же пиксель в массиве может содержать землю, воду и бекграунд. На основе массива pix создается текстура tex_level, сам массив pix нам ещё пригодится.

Слева готовая текстура tex_level, а справа она же, но в игре. Камера в стартовой позиции.

Чтобы было удобнее продвигаться дальше, будем выводить только R канал из tex_level, т.е. только землю.

Для начала нужно избавиться от этих гигантских квадратов. Для этого массив pix перед тем, как его передать в текстуру tex_level следует размыть по Гауссу (радиус размытия подбирался опытным путем). Теперь всё та же локация выглядит уже куда лучше:

Слева земля до размытия, справа после.
Техническая деталь: перед размытием надо растянуть в 2 раза массив pix так, чтобы исходный пиксель занимал бы уже 2х2 пикселя в растянутом массиве.


Но граница земли здесь очень размыта. Для понимания процесса превращения размытой границы в четкую (назовём этот процесс фильтр четкой границы) рассмотрим одномерный случай, т.к. он аналогичный. Тогда размытая граница земли будет выглядеть примерно так:

Вычтем из этого графика 0.5, домножим на какое-нибудь большое число (в данном проекте это 50) и обрежем (операция clamp) по границе [0; 1], т.е. всё, что меньше 0 превращается в 0, а всё, что больше 1 превращается в 1:

В итоге белый цвет не мгновенно переходит в черный (это важно).

Теперь проделаем все эти операции с нашей текстурой tex_level. Пусть в level_color хранится выборка из этой текстуры, тогда фильтр выглядит так: clamp((level_color.r – 0.5) * 50.0, 0.0, 1.0)

Гораздо лучше, а если внимательно присмотреться, то можно увидеть, что на границе раздела двух сред отсутствует алиасинг. Но такая граница слишком гладкая и плавная, давайте же добавим к ней немного шума. Для этого была сгенерирована текстура с шумом Перлина (параметры шума подбирались опытным путем), назовём её noise. Текстурные координаты для выборки из текстуры шума больше во много раз, чем текстурные координаты для tex_level. Это означает, что пока мы в игре видим лишь кусочек текстуры tex_level, шумовая текстура повторяется несколько раз в пределах экрана. Теперь просто сложим выборки из текстуры шума и из tex_level и только потом применим фильтр четкой границы:

В левой части tex_level + noise, в правой части фильтр четкой границы.

Техническая деталь: диапазон значений в текстуре noise от 0 до 1, поэтому к выборке из tex_level следует прибавлять (noise — 0.5) * k, где k – коэффициент возмущения границы (в проекте он равен 0.3).

Теперь осталось просто наложить текстуры. Текстура земли уже есть (это просто обычная текстура), а вот воды еще нет, нужно её сперва подготовить.

Алгоритм абсолютно такой же, как и с землей, только вместо выборки из R канала следует делать выборку из B канала, т.к. именно там и содержится вода. Еще одно отличие – это вместо обычного шума применяется анимированный шум (плавно меняющийся во времени) для создания волн на границе воды и воздуха. Создание анимированного шума выходит за рамки данной статьи. В этом этапе применяем текстуру неба, а роль воды выполняет синий цвет (подбирался опытным путем). Все шаги этапа получения слоя с водой проиллюстрированы ниже:

Слева направо: размытая граница воды, анимированный шум плюс фильтр, интерполяция из синего цвета в текстуру неба.

Следующий этап – это рендеринг бекгруанда. На этот раз выборку из tex_level производим из G канала. В этом этапе ничего принципиально нового нет: получаем маску бекграунда и интерполируем текстуру камней (это в данном случае) и текстуру воды из предыдущего этапа. Конечно, есть свои тонкости: на подводную часть бекграунда накладываются дополнительные фильтры, то же самое и для самой воды для придания эффекта толщи воды, но это выходит за рамки статьи. В этом же этапе рендерятся декоративные элементы: рыбки и водоросли. Окончательно слой с бекграундом выглядит так:

Технические подробности: для придания эффекта «шевелящихся водорослей» из-за подводных течений использовалось смещение x-компоненты текстурных координат при рендеринге спрайта с водорослями. Величина этого смещения считывалась всё из той же текстуры с анимированным шумом.

И последний этап – склейка. Получив в начале статьи маску земли, применяем её для интерполяции текстуры земли и слоя с бекграундом. Финальный результат выглядит так:
Скрытый текст

Развитие идеи. Что если требуется накладывать несколько текстур на землю, тогда просто добавляем ещё один слой, в котором пиксели земли раскрашиваем в 4 разных цвета (можно меньше, но не больше). Из этого слоя создается отдельная текстура-маска (4 цвета в слое – 4 цветовых канала в маске), но тогда придется делать дополнительные пять текстурных выборок вместо одной (одна из маски и 4 из соответствующих текстур земли).

Определение коллизий

Если в тайловых играх коллизии определяются достаточно просто: делаем выборку из массива тайлов и проверяем, попал/не попал в непроходимый тайл. То здесь это будет слишком грубо, т.к. теперь визуально нет тайлов, а есть поверхности под разными углами. Кстати, маска земли в сишном коде недоступна (она является всего лишь одним из этапов вычисления на видеокарте). Но у нас есть массив pix, размытый по Гауссу. В элементах этого массива интересен только младший байт, т.к. именно там хранится земля. Визуально этот массив выглядит так (приведён лишь фрагмент массива, попадающий в камеру, на самом деле в массиве содержится вся карта):

Это отличается от картинки с размытой границей, потому что там применялась билинейная фильтрация, а тут лишь сырые значения массива после размытия.

Значения из этого массива напоминают карту высот, можно подобрать такое значение высоты, которое примерно совпадает с визуальной границей земли (подбираем опытным путем). Для более точного определения высоты необходимо использовать билинейную интерполяцию. А если вычислить три высоты в окрестностях некой точки, то можно довольно точно определить градиент в этой точке, а он совпадает с нормалью к визуальной поверхности земли. Нормаль в этой игре использовалась лишь в одном месте – для огибания реактивной струёй поверхности земли:


Динамичная карта

Итак, первая проблема, поставленная в начале статьи, решена: никаких тайлов не видно, одни неровные скалистые пейзажи. А как быть с движущимися элементами? Это покажет вторая игра – аналог super meat boy:

Здесь много подвижных элементов: циркулярные пилы, двигающиеся по прямой или вращающиеся вокруг центра, перемещающаяся платформа с шипом и пилой, двери, рассыпающиеся тайлы. А пилы ещё имеют разный размер.

Процесс рендеринга полностью аналогичен первой игре, поэтому ограничимся рассмотрением формата карты. Карта из видео выглядит так (увеличено в 5 раз):

Данная карта состоит из шести (!) слоёв (всего в игре есть пять разных типов слоёв, все они здесь представлены). В отличие от предыдущей игры количество слоёв здесь может быть любым. В левом верхнем углу есть набор пикселей (их ровно столько, сколько и слоёв). Они-то как раз и задают тип слоя (это позволяет не заботиться о порядке и количестве слоёв). Первые два слоя очевидны: слой объектов – взаимодействующие элементы с игроком (земля, шипы, пилы, старт, выход, рассыпающиеся тайлы) и слой бекграунда. Четвёртый слой тоже, как и первый, является слоем объектов (4-й пиксель в левом верхнем углу тоже черный). Пришлось вынести некоторые объекты в этот слой, потому что они пересекались с другими объектами (теоретически одинаковых слоёв может быть сколько угодно).

Техническая особенность: в текстуру tex_level помещается только замля и бекграунд (воды в этой игре нет), а все остальные объекты считываются из файла уровня в массив.

Рассмотрим третий слой. Здесь находятся красная и синяя дверь с соответствующими ключами. Так-то двери – это тоже объекты, но помещать их в слой объектов нельзя, потому что красный и синий цвет в этом слое уже заняты соответственно под шипы и под центры вращений (о которых ниже). А вообще, в этом слое отмечаются группы тайлов. Тайлы из одной группы имеют один цвет, и они все смежны друг с другом. Бывают два вида групп:
  • Перемещающаяся группа. Все тайлы этой группы синхронно перемещаются (зеленый цвет). Группа содержит один главный тайл (сине-зеленый цвет), для которого в другом слое назначается траектория и скорость. В этой карте одна большая группа, в которую входит земля (становится что-то вроде тележки) с шипом и пилой. И четыре одинарных – только одна пила перемещается в каждой из них.
  • Вращающаяся группа (серый цвет)

В слое объектов (в данном случае в 4-м) синим цветом отмечаются центры вращения для вращающихся групп (здесь только один центр действительно попал во вращающуюся группу из третьего слоя, остальные же играют роль декоративного элемента, т.к. они тоже рендерятся). Ещё во вращающуюся группу попали две пилы (желтый цвет в 4-м слое). Именно они и вращаются вокруг центра вращения.

В пятом слое указываются размеры пил в градациях красного. Если для пилы отсутствует красный пиксель из этого слоя, то размер её берется по умолчанию. А в шестом слое находятся траектории и скорости для перемещающихся групп в градациях серого, ну и скорости и направления для вращающихся пил. В некоторых слоях есть посторонние цвета, которые в данном слое не участвуют, при загрузке карты они просто игнорируются (например, почти во всех слоях есть черные пиксели земли, они были нужны лишь при составлении карты, для навигации относительно них).

Развитие идеи. Теоретически с помощью Paint можно создать карту для 3D-шутера, файл карты будет состоять из матрицы слоёв. Строка этой матрицы соответствует высоте слоя в игре, а в столбцах содержатся слои одного типа. Например, в 1-м столбце будет геометрия карты (один слой – это срез карты на данной высоте), во 2-м столбце можно назначать текстуры с помощью ключевых цветов пеинта, в 3-м расставлять объекты и т.д.

Вот, пожалуй, и всё. Надеюсь, тема «редактор карт из Paint» раскрыта.

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 27

    +9
    Самое забавное во всем этом, что редактор, который бы позволил делать также карты можно написать самому за один вечер. Только для каждого квадратика хранить не несколько байт с цветом, а данные у вдобном для программы виде и любом количестве.

    Подобный подход сам использовал. И не однократно, но он подходит разве что для прототипирования. Для левел-дизайнера это котироватьяс не будет вообще никак, так как тут даже украшательства нельзя воткнуть самому. А усложнение уровня путем создания нескольких картинок, вообще сделает для дизайнера это адским испытанием.

    Но за статью всёравно спасибо, почитать интересно.
      +8
      Есть редактор Tiled — бесплатный, открытый, кроссплатформенный.
      www.mapeditor.org/
        0
        жаль только что в этом редакторе игры вида minecraft не отредактируешь. Т.к он основан на локациях.
        +1
        Мм, ну я надеюсь все эти манипуляции хотя бы не в рантайме при загрузке уровня происходят?
          0
          Про какие манипуляции идет речь? Применение шума + фильтр — в рантайме в шейдере, а, например, размытие по Гауссу — при загрузке
            +1
            А это разве не жутко медленно? Особенно применение полноэкранного тяжелого шейдера в рантайме. Не лучше бы это всё делать при сборке ресурсов игры и хранить итоговую текстуру?
              +6
              Ну раз уж уровни в Paint'е делаются, почему бы данные в риалтайм не процессить? Только хардкор! :)
                +1
                вообще не медленно, игра выдает 60 кадров даже на iphone 4. Если заготовить при сборке, то подводные водоросли уже не анимировать, на поверхности воды волны будут статичными, а памяти на такую текстуру потребуется примерно в 1165 раз больше (если я правильно посчитал)
                  +3
                  Ну водоросли можно отдельным шейдером анимировать — вряд ли разница будет заметна. Аргумент насчет веса текстур я еще могу понять, но по крайней мере итоговую текстуру можно было бы отрендерить в статичную текстуру при загрузке и не напрягать GPU лишний раз. Оно-то может 60 фпс и выдает, но и батарею кушать будет больше, чем при пре-рендере
                  0
                  если софтварно писать эти фильтры, то скорее всего медленно будет, а через шейдеры очень быстро, они параллелятся очень хорошо.
                    0
                    Ну, понятно что реалтайм оно выдюжит. Другое дело, что это совершенно неоправданная растрата ресурсов, что важно для мобильного устройства.
                    UPD: Ну и никто не мешает воспользоваться рендером в текстуру и отрисовать быстро через шейдер.
                      0
                      Так, мне эти разговоры про рендер заранее надоели.
                      Возьмем самый маленький уровень (он же 1-й)
                      Его размер 47х33 тайла
                      На экран попадает ровно 15 тайлов по горизонтали (на айпаде), рендеринг произвожу в текстуру 1024х768
                      Т.е. один тайл занимает примерно 1024/15=68.3 пиксела (примерно 70) в ширину, а он еще и квадратный, т.е. 70х70
                      Т.о. чтобы сохранить пиксельность уровня нужно заготовить заранее под него текстуру 3290х2310
                      Теперь возьмем самый большой уровень 91х196. Для него уже потребуется текстура 6370х13720, тогда как на моем айпаде 4 максимальный размер текстур 4096х4096. Как вариант, можно разбить эту текстуру на много маленьких (1024х1024 например) так, чтобы все они покрывали уровень. Один фиг, большой уровень потребует 6370х13720х4=350М
                      Даже если все это таки сделать, шейдер уровня будет нетривиальный (не, не просто так взять выборку из текстуры и поместить на экран). Нужно произвести смешивание со скайбоксом, На участке, где вода (а её кстати где хранить в большой текстуре, она ведь пересекается с бекграундом, альфаканал уже занят под маску скайбокса) произвести искажений бэка и водорослей и «замутнить» бэк (типа толща воды). А как сделать выплывание рыбок из-за земли, но поверх бэка? (бэк и земля ведь не отдельно хранятся, а в большой текстуре) Обрезать? Как? Хранить землю и бэк таки в разный текстурах? Ладно, тогда 700М.
                      Оно того стоит? Тогда как я с помощью шейдера рендерю нужный мне кусок уровня с 60фпс

                      update: только что вспомнил, разрешение маски уровня апается в два раза, поэтому умножаем память еще в 4 раза
              +11
              Это все напомнило мне детство.
              Помн лет в одинадцать (примерно 1991 год) написал какую-то простенькую леталку-стрелялку на компилируемом бейсике на писюке.
              Но Писюки тогда были не очень доступны. Я ходил в какой-то институт где работали знакомые, игрался за машинкой с зелено-черным монитором (черно-белые были только у крутых). Никаких жестких дисков — только дискеты. Комп с жестким диском на 20мегабайт был только один и к нему меня не пускали.

              В общем доступ был ограничен, экран одноцветный… А дома стоит Спектрум. Цветной.
              Портировал код один в один благо диалекты бейсков не сильно различались.
              Но восьмибитный проц да интерпретируемый бейсик сделали задачу неосуществимой. Мои полностью рандомные горы на писюках требовали солидной задержки, а тут двигались столь медленно, что играть было нереально.

              Альтернатива портирования всей игры на ассемблер меня не привлекала, хоть я ассемблер и знал и писал на нем небольшие куски для усиления. Вариант выноса только блока рисования гор тоже не помог — я вызывал системную процедуру рисования линий, и это все равно было медленно.

              Тогда я решил «испортить» качество гор заменив их на четыре вида спрайтов — полностью твердый, полностью воздух и два варианта наклона — влево и вправо. Вывод таких «символов» с перегруженным шрифтом оказался заметно быстрее, плюс ширина блока сократилась в восемь раз (ширина символа).

              В результате такой оптимизации (первой в моей жизни) я смог остаться в рамках бейсика и получить приемлимую производительность (даже задержку ввел небольшую).

              Вот забавно — сейчас можно рендерить по живому не заморачиваясь о производительности, а тогда приходилось выкручиваться и рендерить по живому потому что места для заранее сгенеренных текстур тупо не было. Магнитофоны были слишком медленными, а дисководы были не у всех…
                +1
                В 11 лет знали asm и basic… кошмарно подумать, что вы знаете и делаете сейчас. Я-то думал, что более-менее разбираться в С в 13 лет было уже очень круто.
                  0
                  Это вообще вопрос времени. Сейчас люди в 20-25 лет знать не знают что такое ассемблер и с трудом пишут на С. Им подавай высокий уровень. Джаву или шарп.
                  А вот когда я писал свои первые программки (бесполезные до дури, разумеется, в шесть мои-то лет), ничего кроме встроенного в commodore64 бейсика попросту не было. А все почему, потому что в 89м году были другие средства разработки, нежели сейчас :)
                    0
                    Вы правы, все не от возраста зависит, а от окружения… у меня, например, с 1994 года был 386-й, я на нем, конечно же, играл, хотя отец иногда показывал мне простые программки. Потом, в 2000 году, дома появился современный комп, я на нем снова играл. Но в 2001, в кризис доткомов, отец потерял работу и пришлось снова вернутсья на 386-й. Игры типа Wolfenstein после Unreal и Starcraft уже не катили, хотя Prehistoric я прошел целиком без сейвов, вот и не осталось другого выхода как открыть K & R и начать что-то программировать потиху. Сначала скринсейверы, потом простые игры, а потом… купили новый комп и я увлекся 3d, а в программирование вернулся только на первых курсах института. Не знаю зачем вас этим гружу… что-то вспомнилось.
                    0
                    Это только так кажется что страшно.
                    А на самом деле тогда просто время такое было.
                    Впервые я увидел компьютер в девять лет, когда пришел в лабораторию к деду. Дед был доцент на кафедре ВОЛС и они там вечно что-то изобретали, испытывали, рассчитывали… Машинка называлась СМ1800. Характеристики ее я не помню, но там были два пятидюймовых дисковода с маленькой ёмкостью (что-то вроде 90кб) и монитор… монитор был текстовый. Т.е. от системного блока размером с приличную тумбочку шел не аналоговый сигнал а текстовый, и в мониторе уже был свой контроллер который всё это превращал в аналоговый сигнал для трубки.
                    За компом сидел сын дедушкиного коллеги. Пацан был на три года меня старше и с умным видом писал что-то на бейсике.
                    Писал он как оказалось примитивнейшую игрушку — в консоли запрашивается твое имя, тебе говорят «Привет *юзернейм*!», тебя спрашивают мол хочешь ли ты поиграть, если да, то компьютер загадывает число (взятое из констант ибо ГСЧ или не было или пацан о нем не знал), ну и так далее… В общем обычная лапша из print input if goto
                    Поскольку логика «игры» была очевидна, тем более что парниша периодически тестировал, то значение этих трех-пяти команд понять было не сложно. Строки нумерованы… В общем когда парниша вышел в туалет я не удержался и сел за комп. Написал буквально три строчки с еще одним вопросом. Когда парень пришел проворчал с минутку мол он мне не разрешал, но код одобрил и пошел писать дальше… Вот реально ведь ничего сложного — как обезьяна повторил чужие действия.
                    Ну а дальше имея уже какой-то опыт прочитать книжку и разобраться в синтаксисе было не сложно.

                    Использование ассемблера в то время тоже было неизбежным, поскольку на спектруме фактически было только два языка — системный встроеннный бейсик и ассемблер. Да были еще паскали да фортраны, но в реальности на таких малых мощностях машины (48кб ОЗУ из которых часть забирает видеопамять и система, 16кб ПЗУ, восьмибитный проц на пару мегагерц, магнитофон вместо дисковода) использовать их было не особенно реально — компилятор/интерпретатор, исходник, бинарник… при этом бейсик никто не отменял он ведь часть ОС… В общем вариантов особо не было. Поэтому графика писалась на асме.
                    Ну как писалась — брались примеры из книжек и допиливались до своих нужд… Да на писюках был паскаль (я как-то с паскаля начинал). Но там опять таки с библиотеками было довольно туго. Интернета тогда еще не было, поэтому если в моем окружении библиотек не было значит их для меня не было. Зато были книги. И в книгах было прекрасно написано через какие прерывания и каким образом можно получить те фичи которых не было в стандартных библиотеках. Например хотелось использовать SVGA-режимы которые уже были в моем компьютере (чуть позже чем в 91-ом) но в стандартных библиотеках доступен был только VGA. Пришлось писать в паскале небольшие включения ассемблера…

                    Но на самом деле в ассемблере нет ничего такого страшного.
                    Это только кажется что сложно.
                    А когда ты уже умеешь писать лапшу на бейсике то изучить ассемблер не сложно.
                    По сути там что? Пару команд условных/безусловных переходов, копирование в регистр/из регистра сложения/вычитания всякие…
                    Для человека который привык к лапше классического бейсика (с нумерациями строк) в принципе ничего сложного — просто лишаешься небольшого количества синтаксического сахара и вынужден часть механической работы делать сам (планировать память, исправлять адреса переходов изменяя место в памяти, отлаживать в уме или на листочке полученный код и т.п.), но тут много думать не нужно — просто внимательным быть и всё. Ну и если хочешь чтоб код был достаточно шустрым то нужно грамотно планировать память, особенно регистры. Но опять таки — ну нет тут ничего сложного, да и в небольшом куске кода можно и поговнокодить даже по тем меркам.

                    Вот что по настоящему было сложно так это всё это забыть.
                    Да, да, забыть!
                    Я помню свои эмоции когда я впервые столкнулся с языком без goto. Я думал что с меня издеваются, и не понимал как вообще можно жить без прямых переходов. И это я к тому времени уже писал на процедурном диалекте бейсика.
                    Так же самом помню как я сильно возмущался спустя много лет после этого когда в пхп вернули GOTO. Я то помню как это все выглядит, и как сложно было эту лапшу выбить из меня…
                    Так что как по мне так Си в 13 лет знать это круче чем ассемблер в 11. И главное полезнее :)
                  0
                  Вспоминаю, как рисовал уровни для Tux Racer в фотошопе. Изображения являлись картами уровней, вид сверху. На каждый уровень было, кажется, по три картинки: на одной изображался рельеф (яркостью оттенков серого), на другой — тип поверхности, на третьей — объекты.

                  UPD Вот, нашел, как это выглядело: tuxracer.fubaby.com/articles.php?ArticleID=1
                    0
                    Да, я тоже делал как-то. Вроде даже на гитхабе лежит что-то. Это было весело очень, но у меня какие-то неинтересные уровни получались.
                    +1
                    Я раньше обожал делать подобные прототипы каких-то топологий, но еще смешне: на текстовых файлах.
                    То есть рисуется символьное поле, например 40х25, а символ = состояние либо категория

                    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
                    XX           8           XXXXXXXXXXX
                    XXXX   4                    XXXXXXXX
                    XXX  *                 XXXXXXXXXXXXX
                    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX


                    Насколько помню, так прототипировали и описывали движение погрузчиков на складе и т.п. :)

                    0
                    Спасибо за статью, вы на пути генерации процедурных карт). Поделитесь информацией насчет анимированных шумов, может какую-то ссылку дадите? Я так понимаю, что анимировать шум можно увеличив его размерность, т.е. изменять поверхность полны смещаясь по двумерному массиву. Проблемка пока в анимации 2d структур, поскольку 3d текстуру нельзя передать в шейдер на ios. В общем за любую информацию по этой части заранее спасибо.

                    И еще вопрос по части производительности. Воду я так понимаю вы воду рисуете фрагментным шейдером, или что-то недопоняла? У меня самый простецкий шейдер на iphone4 кладет fps ниже 30, если его на весь экран применять. Хотя там по сути совсем маленькая псевдо-анимация шума:

                    noisevec = texture2D(uTexture0, Position.xy);
                    noisevec = texture2D(uTexture0, vec2 (Position.x+noisevec[1], Position.y-noisevec[3]+Offset));

                    Как вариант только отключать retina на 4-ке.
                      0
                      Поделитесь информацией насчет анимированных шумов, может какую-то ссылку дадите?

                      Текстура шума у меня одна и она двухмерная, перед рендерингом воды есть отдельный рендер в текстуру 256х256, там-то как раз и создается анимация, а так же в эту текстуру рендерится реактивная струя (чтобы водоросли искажались на её фоне и для создания всплеска воды при выпрыгивании/нырянии). Анимация делается одной шумовой текстурой: производятся 4 выборки из неё с разными коэфами текстурных коорд (которые зависят от времени), эти выборки суммируются.
                      Воду я так понимаю вы воду рисуете фрагментным шейдером

                      да, вода рендерится в текстуру 256х256, отсюда нет просадки фпс, а качество не страдает, т.к. там нет мелких деталей
                        0
                        Я так понимаю, фрагментый шейдер вызывается по количеству точек на экране, и размер текстуры тут не имеет особого значения. Поэтому у меня пока получается, что если изображение на пол-экрана то fps падает, вне зависимости от детальности прорисовки. Наверное, я что-то не так понимаю. Вы opengl 2 используете?
                          0
                          точнее по количеству точек на рендертаргете, разрешение которого я и выставлял 256х256.
                          Использовал ГЛ 2
                            0
                            Спасибо за ответ! Это вы ловко придумали промежуточный рендеринг в отдельную текстуру с низким разрешением. Ведь такие ситуации часто встречаются.
                      0
                      Игра не «PixelJunk™ Shooter» случайно?

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                      Самое читаемое