Разработка игры в 115 кб — хаки, баги и досада


В начале ноября я участвовал в 115-ом по счете конкурсе сообщества Independent Games Developers Contests (IGDC), темой которого была разработка аркадного шутера с лимитом в 115 килобайт за неделю. Под катом история разработки игры на OpenGL + Free Pascal, эксперименты с LZO, обход багов компилятора FPC для uFMOD, простейшая генерация текстур и досадный баг на видеокартах NVidia, который все испортил.

Видео, бинарник для Windows и исходный код также прилагаются — ищите в конце статьи.

Лирическое вступление


Разработка игр — мое основное, любимое и очень давнее хобби. Я кручусь в любительском gamedev без особых успехов, громких релизов и титанических долгостроев около 10 лет. Замороженных проектов много, доведенных до ума — единицы. В какой-то момент я отчаялся, что у меня ничего не выходит. А потом осознал, что мне нравится не только конечный результат, но и сам процесс разработки игр. С этого момента жить стало спокойнее, но я все еще не отпускаю мысль, что когда-нибудь пересилю себя и выведу какой-нибудь проект на коммерческий уровень.

В какой-то момент я набрел на сообщество IGDC, на котором проводятся короткие (от пары дней до 3 недель) конкурсы по разработке игр на заданную тему. Очень, знаете ли, теплые и ламповые конкурсы, в которых главное — участие, а не приз. Полученный опыт и удовольствие от проделанной работы, а не маркетинг и монетизация.

В наше время, когда порог вхождения в gamedev снизился в разы, и поток откровенно неудачных игр заполоняет мобильные платформы, авторы которых мечтают заработать на безбедную жизнь очередным Flappy Bird… В такое время трудно найти людей, занимающихся разработкой игр ради удовольствия, а не выгоды.

Конечно, есть могучий Ludum Dare, но его хардкорные сроки пока что идут вразрез с моей семейной жизнью.

Начало


Итак, 7 ноября 2014 г. на сайте сообщества объявляется очередной конкурс. Условия:

  • «Пыщ-пыщ» и враги — именно такими словами Ведущий конкурса охарактеризовал аркадный шутер
  • Размер — строго до 115 килобайт, ведь конкурс — 115-й по счету
  • Срок — неделя

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

Ограничение неприлично большое для true demoscene (4к, 32к...), но достаточное, чтобы как следует «извратиться». Беглый анализ средств разработки дает довольно внушительный список того, что укладывается в эти требования:

  • Flash
  • html5 + js
  • С, C++, C#
  • Delphi, FreePascal
  • ...

За бортом остаются Unity, Cry Engine, Unreal Engine, JVM-based языки (требуется предустановленный jre), а также большая часть игровых конструкторов.

О Flash
Несмотря на то, что для Flash необходим установленный Adobe Flash Player, он все же разрешен для использования, в качестве исключения (считается, что Adobe Flash Player все же стоит у большинства). Так сложилось исторически.

За свою жизнь мне удалось попробовать много языков и технологий, и большая часть из списка выше мне знакома не понаслышке. Но ваш покорный слуга выбрал не самый простой вариант — Free Pascal. Почему не самый простой?

Во-первых, в 2014 году Free Pascal (как и Delphi) считается немодным — как следствие, компилятор FPC имеет мало пользователей и немало багов, несмотря на Open Source и кроссплатформенность. Во-вторых, размер скомпилированного ехе у связки Lazarus IDE + FPC — повод для отдельной страницы в wiki. В-третьих, очень мало синтаксического сахара, что остро ощущается, когда постоянно используешь много других языков и технологий.

Конечно же, есть и плюсы:

  • Правильно приготовленный ехе самодостаточен, при этом сравним с ехе от С/С++ со статической линковкой CRT
  • С настройками по умолчанию, не позволяет выстрелить себе в ногу, как в С/С++
  • С нужными настройками отстреливает напрочь обе ноги (что иногда хочется)
  • Совершенно случайно, у меня уже есть мини-фреймворк на Free Pascal + OpenGL

И я уже делал на нем вольный ремейк Lunar Lander


Поехали!



Первым делом я определился с концептом будущей игры — аркадный 2D-шутер с видом сверху, в котором игрок управляет «танком» и всячески отстреливает толпы врагов, с которых валятся бонусы для еще более веселого отстрела врагов. Вакхналия продолжается, пока смерть не разлучит вас с вашим альтер-эго. Ближайший аналог — Crimsonland.

Привычным движением откомпилировав шаблон, я создал себе первую проблему — скомпилированный ехе с моим фреймворком с учетом всех хитрых опций компилятора занимал 120 килобайт. Конечно, с учетом того, что фреймворк умеет (и держа в уме что это все-таки FPC) — это даже достижение. Но нас это абсолютно не устраивает, поэтому безжалостно режем ехе с помощью UPX — 48 килобайт. С этим уже вполне можно работать.

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

Внедряем LZO


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

Поэтому задача — выводить текст на экран силами OpenGL. Не прибегая к архаичному способу вывода векторного текста, следует использовать растровые шрифты (Bitmap Fonts). Мой фреймворк уже имел поддержку вывода текста с использованием заранее сгенерированных и заботливо «запеченых» растровых шрифтов. Задача решена?

Коротко о реализации
Есть собственная велосипедная утилита, которая пакует нужные символы относительно компактно, а затем «запекает» в bmp-файл, в конец которому безжалостно дописывается служебная информация о метрике символов (координаты, размер, оригинальный размер, etc). Любой графический редактор не видит подвоха и вполне корректно открывает файл. Еще бы научить эти самые редакторы не перезаписывать весь файл целиком при сохранении, и можно было бы накладывать на такой шрифт пост-эффекты…


Нет, задача усложняется. Полученный таким образом файл с русскими и латинскими буквами (плюс спецсимволы и цифры) занимал 135 килобайт. Убираем русские символы, уменьшаем физический размер самого шрифта, изображение уменьшается вдвое по одному из измерений и, соответственно, вдвое в размере — 67 килобайт. Но это все равно никуда не годится, так как в сумме с «пустым» проектом это дает ровно 115 килобайт.

Сейчас я осознаю, что наиболее правильным и простым шагом было бы просто взять и генерировать шрифт прямо при запуске, из системного шрифта, благо «копипаст» кода несложен. Более того, в моем предыдущем фреймворке именно так шрифты и генерировались — в «рантайме» из системных шрифтов или otf/ttf файлов.

Но душа хотела романтики, а пятая точка — мучений. И я вспомнил, о том, что товарищ XProger в далеком 2010 году совершил акт насилия над библиотекой MiniLZO, дернув ее дамп и обернув его в несложные asm-инструкции. Выглядит это примерно так, в случае с извлечением:

function lzo_decompress(const CData; CSize: LongInt; var Data; var Size: LongInt): LongInt; cdecl;
asm
  DB $51
  DD $458B5653,$C558B08,$F08BD003,$33FC5589,$144D8BD2,$68A1189,$3C10558B,$331C7611,$83C88AC9
  DD $8346EFC1,$820F04F9,$1C9,$8846068A,$75494202,$3366EBF7,$460E8AC9,$F10F983,$8D83,$75C98500,$8107EB18
  DD $FFC1,$3E804600,$33F47400,$83068AC0,$C8030FC0,$83068B46,$28904C6,$4904C283,$F9832F74,$8B217204,$83028906
  DD $C68304C2,$4E98304,$7304F983,$76C985EE,$46068A14,$49420288,$9EBF775,$8846068A,$75494202,$8AC933F7
  DD $F983460E,$C12B7310,$828D02E9,$FFFFF7FF,$C933C12B,$C1460E8A,$C12B02E1,$8840088A,$88A420A,$420A8840
  DD $288008A,$113E942,$F9830000,$8B207240,$FF428DD9,$8302EBC1,$C32B07E3,$1E8ADB33,$3E3C146,$2B05E9C1
  DD $D9E949C3,$83000000,$2F7220F9,$851FE183,$EB1875C9,$FFC18107,$46000000,$74003E80,$8AC033F4,$1FC08306
  DD $F46C803,$FBC11EB7,$FF428D02,$C683C32B,$8369EB02,$457210F9,$D98BC28B,$C108E383,$C32B0BE3,$8507E183
  DD $EB1875C9,$FFC18107,$46000000,$74003E80,$8ADB33F4,$7C3831E,$F46CB03,$FBC11EB7,$83C32B02,$D03B02C6
  DD $9A840F,$2D0000,$EB000040,$2E9C11F,$2BFF428D,$8AC933C1,$E1C1460E,$8AC12B02,$A884008,$88008A42
  DD $51EB4202,$7206F983,$2BDA8B37,$4FB83D8,$188B2E7C,$8904C083,$4C2831A,$8B02E983,$831A8918,$C08304C2
  DD $4E98304,$7304F983,$76C985EE,$40188A20,$49421A88,$15EBF775,$8840188A,$188A421A,$421A8840,$8840188A
  DD $7549421A,$8AC933F7,$E183FE4E,$FC98503,$FFFE4284,$46068AFF,$49420288,$C933F775,$E9460E8A,$FFFFFECA
  DD $8B10552B,$10891445,$75FC753B,$EBC03304,$FFF8B80D,$753BFFFF,$830372FC,$5B5E04C0,$90C35D59
end;

… и подобное колдунство для собственно сжатия. Это отлично работает (хотя у меня получилось завести это не сразу), но рекомендовать такое для production-кода не стал бы. Есть легкое неудобство при отладке…

После сжатия шрифта получаем 17 килобайт вместо 67. А могли бы и 2-3 килобайта, если бы я просто внедрил генерацию на лету..


Используем uFMOD для вывода звука


Никто не хочет играть в игры без звуков или, хотя бы, музыки. До этого конкурса у меня был опыт работы с библиотекой bass, однако, ее пришлось оставить за бортом — необходимая dll съедала аж 97 килобайт. В отчетной теме конкурса упомянули про uFMOD — миниатюрную библиотеку для вывода xm-музыки, написанную на ассемблере. Забегая вперед, скажу, что ее внедрение в проект в итоге практически не повлияло на размер ехе-файла.

Но был один маленький нюанс. На более-менее современных версиях компилятора FPC (выше 2.2.х) данная библиотека не работала. И проблема кроется в неоднозначном поведении линковщика. Сомневаюсь, что смогу максимально верно описать технические аспекты данной проблемы — иными словами почему external-функции, объявленные в заголовочном файле, не видны для подключенного тут же объектного файла. Такое поведение остается на совести разработчиков компилятора. Приведу пример «обхода» данного поведения для одной из функций.

Было так:

function waveOutClose(hwo:Pointer):LongWord; stdcall; external 'winmm.dll';

А пришлось оборачивать это так:

function my_waveOutClose(hwo:Pointer):LongWord; stdcall; external 'winmm.dll' name 'waveOutClose';

function _waveOutClose(hwo:Pointer):LongWord; stdcall; public name 'waveOutClose';
begin
  Result := my_waveOutClose(hwo);
end;

И так для пары десятков необходимых библиотеке функций. Уточню, что я взял реализацию uFMOD через winmm, как самую легковесную и простую в использовании. Из минусов простоты — она позволяла проигрывать лишь один поток одновременно. Тем самым в моей игре появилась музыка, но от звуков пришлось отказаться.

Собственно, сам xm-трек взял вот тут, после чего утилитой от uFMOD превратил его в вот такой pas-файл, что сэкономило мне еще чуть-чуть места.

Генерация текстур


Перефразируя классика — какой demoscene-проект обойдется без генерации текстур? Изначально, я хотел опустить данную тему — уж больно просто и «в лоб» я сделал генерацию целой одной(!) текстуры. Но, быть может, кому-то из новичков пригодится подобный подход.

Практически для всех спрайтов в игре используется одна и та же текстура:



Просто полосатая текстура с «бордюром» вокруг для большей эстетики. С учетом color tint (то есть «домножая» нужный цвет на такую текстуру) получаем полосатые текстуры любых цветов.

Код генерации мне совершенно не нравится, его явно можно написать более оптимально. Более того, есть стойкое чувство, что бордюр рисуется неверно.

function TGame.GenerateTexture(aWidth, aHeight, aBorderSize: Integer): TglrTexture;
var
  m, m_origin: PByte;
  i, j: Integer;
  value: Byte;
begin
  m := GetMemory(aWidth * aHeight * 3);
  m_origin := m;
  for j := 0 to aHeight - 1 do
    for i := 0 to aWidth - 1 do
    begin
      if (i < aBorderSize) or (j < aBorderSize)
        or (i > aWidth - aBorderSize - 1) or (j > aHeight - aBorderSize - 1) then
        value := 196
      else
        if ((i + j) mod 16) >= 8 then
          value := 255
        else
          value := 196;
      m^ := value; m+=1;
      m^ := value; m+=1;
      m^ := value; m+=1;
    end;
  Result := TglrTexture.Create(m_origin, aWidth, aHeight, tfRGB8);
end;

Для разнообразия, оттенок красного у врагов слегка варьируется с помощью random().

Досадный баг на NVidia


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

Но один за другим конкурсанты отписываются, что моя игра работает у них некорректно — «танк» игрока не виден в принципе, не видны многие вражеские танки, иногда они мелькают. Врагов можно определить только по дыму из выхлопной трубы. Такие проблемы проявляются у всех конкурсантов на видеокартах Nvidia. Более того, один из конкурсантов имеет конфигурацию идентичную моей, но у меня баг не проявляется вовсе. Кому-то помог запуск в режиме совместимости с Windows 95(!), но таких были единицы.

Я выкладывал разные билды (что уже слегка противоречит правилам конкурса), подчищая все подозрительные места в коде, советовал разные настройки, но все было тщетно. Наконец, один из участников, самый дотошный, за что ему большое спасибо (привет, pelmenka!), обнаружил причину — если выключить в панели управления Nvidia потоковую оптимизацию (threading optimization), то игра работает корректно. Досада в том, что у меня такая настройка выключена с незапамятных времен, когда она становилась причиной BSOD-а в некоторых играх.

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

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

  • Потоковая оптимизация приносит больше проблем, чем пользы. Несложный поиск «nvidia threading optimization» дает ссылки на игровые форумы, где настоятельно советуют отключать данную настройку во избежание «моргания» игр
  • Нет никакой спецификации, которая бы объясняла, что делает данная оптимизация на уровне драйверов (или есть?)
  • Некоторое количество тем от инди-разработчиков, жаловавшихся на баги при включенной потоковой опимизации. Без ответов, кроме «просто выключи ее, приятель»

Наконец, мое внимание привлекла тема, в которой жаловались на некорректную работу функции glBufferSubData при включенной Штуке, Которую Нельзя Называть. Это дало мне зацепку, и через некоторое время (дебаги, проверки) я вычленил суть проблемы:

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

При включенной потоковой оптимизации драйвер NVidia по одному ему ведомым признакам иногда (всегда?) помещает вызовы данной функции в отдельный поток и немедленно возвращает управление, что приводит к плачевному результату. Сколько данных успеет «залиться» в буфер, прежде чем пойдет его отрисовка — неизвестно. И OpenGL-драйвер от Nvidia не видит в этом проблемы. Опережая ваш вопрос, я отвечу: нет, размер пересылаемых данных ничтожно мал, пара килобайт (особенно по сравнению с пропускной способностью шины), поэтому дело далеко не в жирных данных.

Спецификация OpenGL не говорит нам о том, что данная функция может быть запущена в отдельном потоке. Личная инициатива от ребят из Nvidia?

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

А в моем случае один буфер используется несколько раз за кадр. То есть:

glBindBuffer(GL_ARRAY_BUFFER, BufferId);
glBufferSubData(GL_ARRAY_BUFFER, 0, Size, Data);
glDrawElements(...);
glBindBuffer(GL_ARRAY_BUFFER, 0);
...
glBindBuffer(GL_ARRAY_BUFFER, BufferId);
glBufferSubData(GL_ARRAY_BUFFER, 0, OtherSize, OtherData);
glDrawElements(...);
glBindBuffer(GL_ARRAY_BUFFER, 0);

И вот тут-то вы почувствуете потоковую оптимизацию во всей красе. Что в итоге будет выведено на экран, определяет слепой случай.

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

В: Почему бы не объединить данные и не отрисовать за один раз?
О: Между этими вызовами есть отрисовка других элементов, менять порядок отрисовки нельзя.

В: Почему бы не использовать разные буферы?
О: Данные в буфере обновляются каждый кадр, держать несколько буферов — трата ресурсов

Итог


В итоге я получил четвертое место на конкурсе, хотя вполне мог бы побороться за второе-третье. Досаду вызвал не тот факт, что я пролетел мимо «тройки» лидеров, а скорее осознание того, что я «запорол» годную игру и 7 дней своей работы одной маленькой неприятностью.

Короткое видео игрового процесса:



Суммарный размер релиза составил почти 80 килобайт. В них входит:

  • 62,0 кб — ехе
  • 17,3 кб — шрифт
  • 0,52 кб — шейдеры

Скачать релиз (все необходимые исходники прилагаются).
Исходники на github
Share post

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 36

    +7
    Мне бы тоже было бы крайне обидно. Но могу сказать, что получилось очень даже годно =) А это отличный результат =)
      0
      У вас ещё 35 килобайт «свободных» осталось, впечатляет. Похоже, можно добавить фон, препятствия и «прокачку», да ещё килобайт 15 останется)
        +3
        Ага, добавить перки, боссов и получится как раз Crimsonland
          0
          Можно попробовать :) хотя по графике я явно не догоню.
        0
        Самый прикол что у меня на компьютере со встроенной видюхой тоже не видно танков. Любопытно.
          0
          Странно, потому что разрабатывалось в основном как раз на встроенной Intel. Если не трудно — скиньте лог, который появляется рядом с ехе. Можно в личку скопировать, он небольшой
            +1
            Скриншот:
            Скрытый текст

            Лог чистый:
            Скрытый текст
            :: Start. Tiny glr version: 0.1 :: stable
            :: FileSystem: pack files found at "": 0
            :: Graphics information
            Vendor: Intel
            Renderer: Intel® HD Graphics
            OpenGL: 3.1.0 — Build 6.14.10.5415
            GLSL: 1.40 — Intel Build 6.14.10.5415
            :: FileSystem: start reading resource «default assets/SpriteShaderV.txt» directly from file
            :: FileSystem: read successfully
            :: FileSystem: start reading resource «default assets/SpriteShaderF.txt» directly from file
            :: FileSystem: read successfully
            :: Texture (ID = 1) load started
            :: Texture (ID = 1) load completed
            :: Initialize completed

            :: FileSystem: start reading LZO resource «shooter/font.bmp» directly from file
            :: FileSystem: read successfully
            :: Texture (ID = 2) load started
            :: Texture (ID = 2) load completed
            :: Texture (ID = 3) load started
            :: Texture (ID = 3) load completed
            :: Appication loop started
            :: Appication loop finished
            :: End. Errors: 0, warnings: 0


            Мобыть конечно дело в WinXP, но фиг его знает.
              0
              Да, симптомы один в один, как у конкурсантов. И явно дело в многоразовом использовании буфера, частицы рисуются в отдельном буфере и за один раз. Я постараюсь на днях собрать новый билд (или несколько), ничего если отправлю его (их) вам, не сильно затруднит?
                +1
                Без проблем
          0
          «А в моем случае один буфер используется несколько раз за кадр.» Да, это вы зря, с таким подходом может быть масса проблем. Лучший вариант конечно делать один Draw на кадр если вершинная декларация позволяет и использовать один большой буфер в который в конец дописывать свои вершины.
            0
            Привет Daemon! Добро пожаловать на Хабр!
              +5
              Динамика хороша. Лучше, чем в многих современных гигабайтных играх.
                0
                Вы молодец! Судя по видео, игра получилась даже интереснее некоторых своих полноразмерных аналогов.
                  0
                  Классно, но не понял, почему шрифт занимает так много? На скрине картинка 256*128 = 32768 пикселей, в режиме 1 бит на пиксель это всего 4 килобайта.
                  Когда делал в школе игры под дос, точно так же поступал — писал виндовую утилиту для генерации растровых шрифтов. Только хранил символы 8х16 пикселей отдельно, а не целой картинкой.

                  Паскалевская процедура на ассемблере
                  Procedure PutChar32(X,Y,C,S:DWord; Symbol:Char);Assembler;
                  Var
                  DX1: DWord;
                  Asm
                  Mov Esi, pFont
                  Movzx Eax, Symbol
                  Shl Eax, 4
                  Add Esi, Eax {Char bitmap}

                  Mov Edi, LFBMem
                  Mov Eax, Y
                  Mul ScreenSX
                  Add Eax, X
                  Shl Eax, 2{<>}
                  Add Edi, Eax

                  Mov Eax, ScreenSX
                  Sub Eax, 8
                  Shl Eax, 2{<>}
                  Mov DX1, Eax

                  Xor Ecx, Ecx
                  Xor Eax, Eax
                  Mov Cl, 16

                  @NextTex:
                  Mov Ebx, 128
                  LodsB
                  Mov Bh, Al
                  Mov Ch, 8
                  ALIGN 4
                  @NextDot:
                  Mov Dl, Bh
                  And Dl, Bl
                  Cmp Dl, 0
                  Je Skip
                  Mov Eax, C
                  StosD
                  Sub Edi, 4
                  Skip:
                  Add Edi, 4
                  Shr Bl, 1
                  Dec Ch; Jnz @NextDot
                  Add Edi, DX1
                  Dec Cl; Jnz @NextTex
                  {}
                  End;

                    +11
                    Хабраюзер «Skip» незаметно затесался в Ваши исходники.
                      0
                      Пишется полноценный битмап в rgba, соответственно 4 байта на пиксель, RGB — всегда ffffff, альфа варьируется. Очень нерационально, верно. Как минимум, надо отрезать RGB, оставлять только альфу. Утилиту планируется научить всяким эффектам, в том числе цветовым, поэтому изначально писалось с полным хранением RGB. Переписывать под конкурс не было времени.

                      И как я отметил в посте, намного меньше по размеру была бы генерация на лету. Может быть даже меньше чем хранение битовой маски.
                      +8
                      Ох, на меня нахлынула лютая ностальгия в комплекте с дежавю :)
                      Когда-то в 2008 году писал похожую игру на конкурс, проводимый mirgames.ru, только ограничение там было более жесткое — не более 64 кб. В итоге у меня родился Crimsonland-подобный топдаун-шутер с итоговым весом сжатого бинарника в 49 кб. Вкратце: жестко заточенный под конкретную эту игру «фреймворк», юзающий OpenGL для графики, DirectSound для звука, и WinAPI для генерации текстур шрифтов и всего остального. Также в игре присутствует полноценная пиксельная графика, честно украденная из древней DOS-игры (+часть графики генерируется при старте) и звуки. Звуки в итоге и занимают большую часть места, без них и без звукового движка игра весила бы по крайней мере в 2 раза меньше. Использовался Delphi 2007, в качестве упаковщика — 20to4 + UPack. В общем-то, приложив некоторое количество усилий, игру можно было бы еще уменьшить по крайней мере раза 2, но смысла возиться с этим я не видел — игра и так влезала в 64кб с большим запасом.
                      Позже еще добавил трекерную музыку в XM через MiniFMOD, сжатый бинарник стал весить 110 кб (.xm с музыкой был довольно жирный — 99кб).
                      Игру также постигла аналогичная вашей проблема — на половине видеокарт от ATI игра упорно падала при старте сурвайвала. Как оказалось, render-to-texture на ATI тогда работал очень хреново, потому я в срочном порядке заменил рендеринг в текстуру на тупой glReadPixels, и все стало работать везде, но… часть голосов я из-за этого тогда тоже недополучил. Но 2 место таки взял %)

                      Ну и если кому интересно:


                      Архив с исходниками+бинарниками:
                      www.dropbox.com/s/q87s3rq8r2g8wm3/extinction.zip?dl=0
                      (К сожалению, исходников последней версии c музыкой не нашел, сохранился только бинарник. Но вроде бы разница только в отсутствии в исходниках поддержки музыки.)
                        0
                        Приглашаем Вас принять участие с Вашей игрой в конкурсе игр для KolibriOS: habrahabr.ru/company/kolibrios/blog/243081/
                          +1
                          Боюсь, я не настолько хорош, чтобы осилить такое шаманство :)
                          Как обстоят дела с у KolibriOS с OpenGL? Только TinyGL и Mesa?
                        +1
                        115кб? Когда-то люди Элиту в 48кб запихивали, а тут 115! А если серьёзно — молодец! Я уже очень давно ушел из программирования, оценить качество работы не могу. Но сам факт старания и стремления… Большинство кодеров давно уже забыли, что такое килобайты, оптимизация и скорость.
                          +2
                          Спасибо! Стремление к минимизации пришло от просмотра товарища XProger. Хотя мне до его трехмерного шутера void в 27 килобайт все еще очень далеко :) Который, кстати, на Delphi.
                          Скриншоты
                          image
                          image
                            +1
                            Ой ну пиристань… у тебя то геймплей есть, молодец! :)
                              0
                              А где можно потрогать этот void?
                                0
                                Тут, но антивирус может ругаться на пожатые exe. Исходники идут в архиве, так что можно пересобрать самому в Delphi начиная с 2006 версии.
                                  0
                                  Впечатляет, но изображение почему-то мерцает сильно.
                            • UFO just landed and posted this here
                            +1
                            Перфектно, молодца :)

                            На будущее, для подобных проектов: есть метод для получения сверхкомпактных .exe (от 1 кб) для Windows, предложенный Максом Феоктистовым (автором Small HTTP Server) на основе компилятора DJGPP, заточенного для генерации .exe, и собственного PE-линкера для Windows. Всё это опубликовано у него на сайте.

                            smallsrv.com/mkpe/ (если не откроется, есть в кэше гугле)

                            Мне удалось прикрутить генерацию .exe данным способом к мультитаргетной среде разработки XDev. Вот пример сверхкомпактной оконной программы с исходниками на языке Оберон-2 (для 32 и 64 бит соответственно):

                            zx.oberon2.ru/forum/viewtopic.php?f=32&t=189#p1180

                            Раз предпочитаете Дельфи, а не Си, то, возможно, стоит попробовать для разработки компактных игр паскалеподобный Оберон. Если решитесь осваивать — потребует времени на примеривание, разработку биндингов. Но потраченные усилия обязательно окупятся — ведь на XDev можно делать программы не только для Win32/64, но и для Linux, Java microedition и ретро-платформ — DOS, MSX, ZX Spectrum. Если интересно, приходите на форум, будем общаться. :)

                            Сейчас портирую на Оберон некоторые игры с ZX Spectrum и DOS, например:

                            Bolder Dash (Владимир Мутель, Turbo C 2.0, DOS): zx.oberon2.ru/dash.htm
                            Дурак (Вячеслав Медноногов, Laser Basic, ZX Spectrum): zx.oberon2.ru/durak.htm
                            Dark Woods (Jocke The Beast, Quick Basic 4.5, DOS, no sources (реверс инжиниринг)): zx.oberon2.ru/forum/viewforum.php?f=26

                            Кто-то игры делает, кто-то портирует. Смысл моей работы по портированию — прояснить алгоритмы, вывести их из малопонятного сильно заточенного под платформу или среду разработки вида в сторону мультиплатформенности. Конечный размер игр (их версий для Спектрума) не может превышать 42 кб даже без упаковки — этот лимит продиктован адресным пространством Спектрума (16 кб занято ПЗУ + 6 кб экранная память; страницами 128 кб-моделей я не пользуюсь). Для Windows (методом Феоктистова) — размер ненамного больше (а с UPX — значительно меньше), просто я сейчас использую для вывода графики библиотеку SDL, а разработка графического движка на WinAPI — только в проекте. uFMOD — отличная библиотека, спасибо за наводку! :)
                              0
                              Не подскажете, насколько важен именно DJGPP в методе Макса Феоктистова? Gcc из DJGPP не хочет запускаться на Win7 x64…
                                0
                                В методе Макса Феоктистова DJGPP занимает ключевую роль. Я использую его для получения сверхмалого размера EXE, но сам Макс писал мне что разработал свой линкер исключительно для производства виндовых приложений в то время когда GCC ещё не умел их генерировать (а MINGW ещё не было), и сегодня Макс советует использовать вместо DJGPP и его линкера CygWin или MINGW. Я ещё использую tcc (Tiny C), который умеет генерировать 32- и 64-битный код для Windows и Linux: для небольших приложений код получается достаточно компактным, но конечно не настолько, как по методу Макса. Для бОльших приложений MINGW выигрывает и по размеру кода, и по быстродействию.

                                DJGPP является программой для DOS, поэтому и не работает под x64. Если хотите, можно попробовать написать батник, который будет вызывать его с помощью DOSBox. У меня в XDev/DosDev подобным образом вызывается Turbo C:

                                github.com/Oleg-N-Cher/XDev/blob/master/DosDev/Bin/compile.bat
                                github.com/Oleg-N-Cher/XDev/blob/master/DosDev/Bin/build.bat

                                Или же используйте виртуальную 32-битную Windows внутри 64-битной.

                                Вам могут понадобиться заголовочные файлы DJGPP для WinAPI. Можно взять из MINGW (правда, их придётся модифицировать, всё-таки DJGPP 2.95 это старая версия GCC). Или воспользуйтесь этим:

                                github.com/Oleg-N-Cher/XDev/blob/master/WinDev/Lib/C/WinApi.h

                                (безошибочность не гарантируется, я делал этот биндинг сам)
                                  0
                                  У меня тоже стоит цель получения сверхмалого ЕХЕ. Сейчас собираю с помощью mingw, после UPX размер 30к. Только TCC мне не помогает. Увидел от него профит только на маленьких приложениях, которые используют stdlib. У меня же чистый WinAPI (-nostdlib, -nostartfiles), так что на ТСС получается и жирнее и медленнее.

                                  Значит, скорее всего какого-то значительного уменьшения ЕХЕ-файла при использовании DJGPP мне можно не ждать?
                                    0
                                    Выигрыш в сравнении с MINGW будет. Но чудес конечно не ждите. Смотрите:

                                    zx.oberon2.ru/forum/viewtopic.php?f=32&t=189&p=1385#p1180

                                    Приложенный в архиве файл MoveWindow.exe занимает, как видите, 3 кб. Что он умеет делать — смотрите в исходнике MoveWindow.Mod и сопоставляйте со своими нуждами. Как по мне — добиться меньшего размера EXE, чем с помощью метода Макса Феоктистова, просто невозможно. Если знаете как — напишите, интересно.

                                    Я бы планировал обязательное уменьшение вашего EXE-шника при переходе от MINGW к DJGPP килобайта на 4 (минимум) до 10-16 (максимум). В пожатом UPX виде разница конечно будет не столь значительная.

                                    Также на простую пересборку вашего кода DJGPP я бы не расчитывал. Скорее всего придётся допиливать и биндинги к API, и код.

                                    Так что думайте, стоит ли овчинка выделки.
                                      0
                                      Не, наверное есть ещё способ добиться сверхмалого размера EXE с помощью Sphinx C-- (Michael Sheker), но это будет не Си, а Си-минус-минус, к которому переходить от готового кода на Си смысла мало, лучше писать сразу на минусах.

                                      www.sheker.chat.ru/

                                      Можно составить мнение о языке Си-минус-минус по статье «Sphinx C-- — язык не для всех»:

                                      www.sheker.chat.ru/c--part1.rar
                                      www.sheker.chat.ru/c--part2.rar

                                      Проект давно не развивается.
                                        0
                                        Посмотрел примеры кода на С--, не увидел цикла for и массивов. Переносить готовую программу на этот язык действительно смысла мало.
                              0
                              Шрифт-мейкер дофига похож на тот, что идет в комплекте с ZenGL — и то и то основано на одном и том же?
                                0
                                Принцип генерации и упаковки шрифта в растр практически у всех движков един, отсюда видимо и схожесть интерфейса. Тут сложно придумать что-то новое.
                                И мой фреймворк, и ZenGL написаны на Free Pascal + Lazarus. Оба рендерят через OpenGL. На этом сходства заканчиваются. Так что в какой-то степени, Да, основаны на одном и том же

                              Only users with full accounts can post comments. Log in, please.