Как создать игру на windows forms

Обновлено: 03.07.2024

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

Возможный сценарий игры

Действующие персонажи: 1) противник (враги — Enemies); 2) НЛО (один из видов противника — Bugs-«жучки»), ограничимся пока одним видом врагов; 3) защитник Земли (игрок — Player).

Место действия. Сражение происходит в космическом пространстве в окрестностях Земли.

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

Игрок. Игрок, находясь в своем корабле, использует свое оружие с лазерным прицелом (blaster) и перемещается в околоземном пространстве, старается сбить НЛО противника. Для управления перемещением игрока используется мышь, стрельба — нажатием левой кнопки мыши.

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

Цель игры — уничтожить максимальное количество НЛО противника (максимальный результат — 100%).

Проектирование классов

Класс Player

Поля класса:
public Point point; // положение игрока в 2D-пространстве
public Size size; // размеры игрока
public Region reg; // занимаемая им область в пространстве
public Pen laser_pen; // свойство оружия
Методы класса:
public void New_player() // задать свойства (параметры) игрока
public void Show_player() // показать его на поле битвы
Содержание методов этого и последующих классов рассмотрим позднее.

Класс Bugs

Поля:
public Point point; // положение НЛО в 2D-пространстве
public Size size; // размеры НЛО
int veloX; // скорость смещения по X
int veloY; // скорость_падения по Y
public HatchBrush br; // кисть для покраски НЛО
public Region reg = new Region(); // занимаемая им область в пространстве
public Boolean life = true; // НЛО жив (true) или мертв (false)
Методы:
public void New_bug() // задать свойства (параметры) НЛО
public void Form_bug() // задать форму НЛО, например, тарелку
public void Move_bug() // задать новое местоположение НЛО

Класс Enemies
Вспомогательный класс BrushColor

Поля класса:
public Color FonColor; // цвет фона
public Color LaserColor; // цвет лазера
public Color DashBug; // цвет штриховки НЛО
public Color KilledBug; // цвет сбитого НЛО
Методы класса:
public BrushColor() // конструктор (настройка цветов)
public HatchBrush New_br(int rch) // кисть для задания цвета НЛО
public Color RandomColor(int rch) // генератор случайного цвета

Класс Form1

Управление игрой. Выберем на панели элементов 4 визуальных объекта: три кнопки — button1 («Старт»), button2 («Лазер: включить/выключить»), button3 («Стоп») и textBox1 для отображения счета игры (Result) и перенесем их на форму. Также добавим 3 невизуальных объекта: timer1, timer2 и imageList1. Объект imageList1 будем использовать для хранения изображений игрока (player). Таймер timer1 будет задавать частоту изменений (минимальный временной такт). Таймер timer2 будем использовать для генерации серий НЛО. Активность игрока свяжем, как указано в сценарии, с нажатием левой кнопки мыши и перемещением ее по экрану — событие MouseClick.

Методы класса Form1 (реакции на события):
а) конструктор формы
public Form1()
б) при загрузке формы
private void Form1_Load(object sender, EventArgs e)
в) старт игры
private void button1_Click(object sender, EventArgs e)
г) включение/отключение лазера
private void button2_Click(object sender, EventArgs e)
д) стоп игры, результат
private void button3_Click(object sender, EventArgs e)
е) один временной такт игры
private void timer1_Tick(object sender, EventArgs e)
ж) генерация серий
private void timer2_Tick(object sender, EventArgs e)
3) попадание НЛО под вертикальный обстрел лазером
private void Form1_MouseClick(object sender, MouseEventArgs e)

Настройка объектов

Для использования полного экрана зададим свойство Form1.WindowState=Maximized.

Подготовим в графическом редакторе изображения игрока размером 100х100 пикселей с именами player.bmp и player1.bmp, например так:

player12

и сохраним их в папке Resourсes проекта. Зададим свойство imageList1.ImageSize = 100;100 и внесем в коллекцию imageList1.Images эти два файла (члены 0 и 1)

Изображения НЛО будет генерировать метод public void Form_bug().

Настройки таймеров:
timer1.Enable=false (выключен);
timer2.Enable=false (выключен);
timer1.Interval=400 (0,4c);
timer2.interval=5000 (5c).

Исходный вид формы (в том числе с не визуальными компонентами) представлен ниже:

форма59

Вместо кнопок можно задать меню из трех позиций: Старт, Лазер, Стоп. Соответственно сменятся и названия методов, связанных с выбором пунктов меню.

Реализация методов класса Player:

Комментарии: Размер изображения определяется через размер рисунка (см. далее метод Form1_Load() ). Левый верхний угол объекта имеет координаты (0,0). Область, занимаемая игроком, прямоугольная. Цвет луча лазера определяется свойством F.bc.LaserColor. Для доступа к объекту bc, расположенному на форме, параметр метода задаем как Form1 F.

б) показать игрока

Комментарии: Метод имеет параметры: Form1 F (для доступа к объекту g и свойству BackColor – цвету фона), int x, int y — новые координаты игрока (x – ось симметрии). Первый оператор снимает защиту с предыдущей области расположения игрока. Также определяется новая область reg. Метод DrawImage(F.imageP, point) обеспечивает рисование игрока, метод ExcludeClip(reg) обеспечивает защиту заданной области до следующего вызова метода. Совет: Уберите первый и последний операторы и посмотрите на изменения в отображении игрока.

Реализация методов класса Bugs

а) генерация одного НЛО

Комментарии: Метод формирует начальные координаты НЛО, его размеры, скорости смещения за 1 такт срабатывания таймера timer1, выбирает цвет кисти для его покраски. Везде используется генератор случайных чисел класса Random. Для задания области reg вызывается следующий метод.

б) задание формы НЛО

в) вертикальное падение НЛО с горизонтальными смещениями

Комментарий: новая область размещения НЛО заполняется на каждом такте срабатывания таймера 1 после изменения координат через метод Form_bug().

Реализация методов класса Enemies

а) настройка серий и создание ссылок на объекты НЛО

Комментарии: В методе задается жестко число серий — 10. Вычисляется число НЛО в каждой серии. Обнуляется счетчик числа генераций (серий) и числа активных НЛО. Создаются ссылки на максимально возможное число объектов.

б) удаление сбитых НЛО

в) смещение и отображение НЛО

Комментарий: Метод в цикле для активных НЛО обеспечивает их смещение и отображение на экране.

г) одна серия НЛО

Комментарий: Метод добавляет новую серию НЛО, каждый из которых имеет свой цвет, размеры и начальное местоположение.

д) подбитые НЛО, выделены F.bc.KilledBug цветом

Комментарий: проверяет попадание объектов под лазерный прицел, отмечает их в свойстве life как false, обеспечивает вспышку НЛО при подрыве.

Реализация методов класса BrushColor

а) кисть для задания цвета НЛО

Комментарий: Метод возвращает кисть класса HatchBrush (шаблон штриховки) из библиотеки System.Drawing.Drawing2D, состоит из одного оператора.

б) случайный цвет

Комментарий: этот метод мы уже использовали ранее в других примерах.

Реализация методов класса Form1

а) конструктор формы

Комментарий: без изменений.

б) при загрузке формы

Комментарии: Номер первой серии = 0. Генерация первой серии НЛО — nlo.Enemy(this). Запуск таймеров. Открыть доступ к кнопке «Стоп», закрыть доступ к кнопке «Старт».

г) Включение/отключение лазера игроком

Комментарий: включение/отключение лазера игроком

д) Стоп. Результат

Комментарии: Остановка таймеров (игры). Помещение игрока в «гараж» (на красном фоне, вывод второго изображения из коллекции imageList1.Images[]), расчет результата игры в процентах, его вывод в окне MessageBox, обнуление числа активных объектов НЛО, открытие доступа к кнопке «Старт», обнуление результата. Игра снова может быть запущена без перезапуска приложения.

е) один временной такт

Комментарии: При срабатывании 1-го таймера производится очистка фона кроме защищенной области под игроком (см. выше метод Show_player(Form1 F, int x, int y)), что позволяет избежать исчезновения игрока. К результату добавляется число сбитых на предыдущем такте НЛО. Отображаются активные (ещё «живые») НЛО и текущий счет игры.

ж) генерация серий

Комментарии: Увеличение номера серии на 1, сокращение на 100 мс интервала выпуска следующей серии, если реализованы все nlo.N_generation, то остановка генерации ( timer2.Stop();) , иначе генерация очередной серии.

з) попадание НЛО под вертикальный обстрел лазером

Комментарии: И, наконец, последний самый главный метод, вызываемый при клике на форме, обеспечивает показ игрока в заданном мышью положении, выстрел из оружия, отметка подбитых НЛО, вспышки при их подрыве.

Интересно, что событие MouseClick демонстрирует взаимодействие объектов трех классов: Form1, Player и Enemies, а опосредовано и всех пяти (+ Bugs и BrushColor).

Развитие игры

Опираясь на пример игры, постарайтесь ее развить.

Например, чтобы столкновение игрока с НЛО приводило к уменьшению счета игры вплоть до ее остановки при ранениях, несовместимых с жизнью игрока.

Другое направление — изменение способов задания объектов, используя базы данных и/или файлы.

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

Четвертое направление — добавление нового вида (класса) противников, отличающихся от безобидных пока НЛО, после чего создайте для них общий класс, от которого они будут наследоваться (принцип наследования).

Не забывайте и про принцип полиморфизма, пусть методы родственных классов называются одинаково, а действуют по-разному.

В этом учебном руководстве вы создадите игру "Подбери пару!", в которой игрок должен подобрать пару скрытым значкам.

В этом учебнике выполняются перечисленные ниже задачи.

сохранять объекты, например значки, в объекте List<T>;

отслеживать состояние формы с помощью ссылочных переменных;

создавать обработчик событий, который можно использовать для нескольких объектов;

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

По завершении приложение должно выглядеть следующим образом.

Игра, которую вы создадите в этом учебном руководстве

Ссылки на руководства

Заголовок Описание
Шаг 1. Создание проекта и добавление таблицы в форму Начните с создания проекта и добавления элемента управления TableLayoutPanel , чтобы все элементы управления были правильно выровнены.
Шаг 2. Добавление случайного объекта и списка значков Добавление объектов Random и List для создания списка значков.
Шаг 3. Назначение каждому элементу управления Label случайного значка Случайным образом назначьте значки элементам управления Label , чтобы каждая игра отличалась от остальных.
Шаг 4. Добавление обработчика событий Click к каждому элементу управления Label Добавление обработчика события Click , изменяющего цвет метки, которую щелкнули.
Шаг 5. Добавление ссылок на элементы управления Label Добавление ссылочных переменных для отслеживания меток, которые щелкнули.
Шаг 6. Добавление таймера Добавьте таймер в форму, чтобы отслеживать время, прошедшее с начала игры.
Шаг 7. Отмена исчезновения пар значков Отмена исчезновения пар значков, если выбрана одинаковая пара.
Шаг 8. Добавление метода для проверки того, выиграл ли игрок Добавление метода CheckForWinner() для проверки, выиграл ли игрок.
Шаг 9. Изучение других возможностей Изучение других функций, таких как изменение значков и цветов, добавление сетки и добавление звуков. Увеличение игрового поля и изменение настроек таймера.


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

Логическая игра — увлекательный и интересный метод развития мышления и логики. Её несомненными плюсами являются наглядность, полезность, доступность и интересность. Такие игры хоть и кажутся довольно простыми из-за незамысловатой графики и сюжета, однако они помогают человеку тренировать внимательность и усидчивость. Логические игры отлично подходят для курсовых работ. Они позволяют наглядно продемонстрировать работу алгоритмов. Существует множество способов реализации подобных игр. Один из них — Windows Forms. Рассмотрим его подробнее.

Windows Forms — интерфейс программирования приложений (API), отвечающий за графический интерфейс пользователя (GUI).

В Windows Forms форма — это визуальная поверхность, на которой выводится информация для пользователя.

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

Windows Forms включает широкий набор элементов управления, которые можно добавлять на формы. Перечислим основные из них:

Данный элемент представляет из себя кнопку и позволяет пользователю щёлкнуть на него для выполнения действия, тем самым, вызывая обработчик событий. Без данного элемента не обходится практически ни одно приложение. На него можно поместить какой-либо текст или же картинку (см. рис. 1). Также настраивается стиль button, стиль шрифта и др.


Рис. 1. Пример Button

Примером использования данного элемента будет переход с одной формы на другую. При нажатии на button срабатывает событие Click в котором мы заранее прописали код перехода на другую форму.

Представляет из себя окошко, в которое помещается изображение. PictureBox используется для отображения графики в формате точечного рисунка, GIF, JPEG, метафайла или значка.

Данный элемент был использован в игре «Крестики-нолики», где игровое поле полностью состояло из объектов PictureBox (см. рис. 2). В программе был написал алгоритм, благодаря которому при нажатии на элемент PictureBox появляется картинка «крестика» или «нолика».


Рис. 2. Игра «Крестики-нолики»

Данный элемент используется для получения и редактирования текста, полученного от пользователя, а также для отображения текста. Элемент можно сделать доступным только для чтения, как, например, label. Также можно отобразить несколько строк, перенести текст по размеру элемента и добавить основные элементы форматирования.

Пример использования — приложение «Калькулятор» (см. рис. 3). Окошко для ввода данных — TextBox. С помощью события KeyPress он был специально настроен таким образом, чтобы можно было вводить только цифры и знаки, используемые в калькуляторе.


Рис. 3. Калькулятор

Представляет из себя мощный и гибкий элемент для представления данных в табличном формате. Его удобно использовать для представления как малого, так и большого объёма данных. Внешний вид легко настраивается заданием значений нескольких свойств. Информация в элементах может представляться в виде символов, а также в виде изображений. В качестве источника данных могут использоваться хранилища данных различных типов. Также данный элемент может работать без привязанного к нему источника данных.

Данный элемент был использован в игре «Судоку» (см. рис. 4). Где игровое поле было представлено в виде таблицы. Данное решение помогло сэкономить время и память, а также упростить реализацию, чем если бы мы использовали любой другой элемент.

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

На рисунках рис. 2 и рис. 4 элемент label используется в виде показа правил обеих игр.


Рис. 4. Игра «Судоку»

Данный компонент вызывает событие через определённые интервалы времени. Изначально в программе задаётся свойство timer.Interval. Если мы хотим получить интервал времени в секунду необходимо написать Interval=1000. Затем запускается Timer, используя при этом метод Start. Через заданный интервал вызывается событие Tick. Для остановки timer используется метод Stop.

Пример использования показан на рисунке рис. 4. Timer отвечает за изменение времени на кнопке.

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

C

Как человеку, выросшему во времена дискет и 56 Кбит модемов, мне всегда нравились небольшие программы. Я мог поместить много небольших программ на дискету, которую носил с собой. Если программа не помещалась на моем гибком диске, я начинал думать, почему: много графики? Музыка? Программа сложная или просто раздулась?

В наши дни дисковое пространство стало настолько дешевым (а огромные флешки настолько вездесущими), что люди отказались от оптимизации размера.

Единственная область, где размер еще имеет значение — это передача: при передаче программы по проводу мегабайты приравниваются к секундам. Быстрое соединение на 100 Мбит может пропускать только 12 мегабайт в секунду в лучшем случае. Когда на другом конце провода находится человек, ожидающий завершения загрузки, разница между пятью и одной секундами может оказать существенное влияние на восприятие. Человек может зависеть от времени передачи либо напрямую: он загружает программу по сети, либо косвенно — бессерверная служба развертывается для ответа на веб-запрос.

Люди обычно воспринимают что-то быстрее 0,1 секунды как мгновенное. 3 секунды — примерно предел непрерывности потока пользователя, и вам было бы трудно удержать пользователя после 10 секунд.

Хотя меньший размер больше не является существенным, он всё равно лучше.

Что такое автономность?

Игра меньше 8 Кб

Мы создадим клон змейки:

Не интересна игровая механика? Не стесняйтесь переходить к интересным частям, где мы сжимаем игру с 65 мегабайт до 8 килобайт за 9 шагов, прокрутите до графика.

Игра будет работать в текстовом режиме, и мы используем поле рисования символов, чтобы нарисовать змею. Я уверен, что Vulcan или DirectX намного веселее, но мы справимся и с System.Console .

Игра без выделения памяти

Структура игры

Начнем со структуры буфера кадров. Буфер кадров — это компонент, содержащий пиксели (или в данном случае — символы), отображаемые на экране:

Мы предоставляем методы установки отдельных пикселей, очистки и визуализации содержимого буфера кадров System.Console . Шаг рендеринга особых случаев несколько символов, так что мы получаем красочный вывод без необходимости отслеживать цвет каждого пикселя буфера кадров.

Мы не можем переборщить с размером фиксированного массива, потому что как часть структуры массив должен жить в стеке, а стеки, как правило, ограничены небольшим количеством байтов (обычно 1 Мб на поток) и 40*20*2 width*height* sizeof(char) — допустимое число.

Этот генератор не слишком хорош, но нам не нужно ничего сложного. Теперь пишем обёртку для логики игры:

Состояния, которые должна отслеживать змейка:

  • Координаты каждого пикселя тела.
  • Длина змейки.
  • Текущее направление движения.
  • Прошлое направление для случая, когда нужно нарисовать символ изгиба вместо прямой линии.

Структура предоставляет метод расширения змеи на один элемент (возвращает false, если змея уже находится на полной длине), метод HitTest для теста столкновений пикселя тела, отрисовки змейки во FrameBuffer и метод обновления положения змеи как ответ на игровой тик (возвращает false , если змея съела себя). Существует также свойство, чтобы установить направление змеи.

Мы используем тот же трюк с фиксированным массивом, что и в буфере кадров, чтобы не использовать new . Это означает, что максимальная длина змеи должна быть постоянной времени компиляции. Последнее, что нам нужно — игровой цикл:

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

Я поместил игру в репозиторий GitHub, чтобы вы могли следить за ней. Файл проекта собирает игру в различных конфигурациях в зависимости от переданного при публикации свойства Mode . Чтобы создать конфигурацию по умолчанию с помощью CoreCLR, выполните:


Il Linker

С этой настройкой игра сжимается до 25 МБ. Хорошее сокращение, но оно далеко от нашей цели.

IL Linker имеет более агрессивные настройки, не выставляемые публично, и они могут работать дальше, но в конце концов, мы ограничимся размером самой среды выполнения CoreCLR coreclr.dll в 5,3 Мбайт. Возможно, мы зашли в тупик на пути к игре на 8 Кб?


В отличие от CoreCLR, Mono также зависит от распространяемой библиотеки среды выполнения Visual C++, недоступной в установке Windows по умолчанию: чтобы сохранить автономность приложения, нам нужно зашить эту библиотеку в приложение. Это увеличивает объем ещё на один мегабайт или около того.

Мы, вероятно, сможем сделать приложение меньше, добавив Il Linker, но тогда столкнемся с той же проблемой, что и с CoreCLR — размером среды выполнения mono-2.0-sgen.dll , он составляет 5,9 МБ. Плюс размер библиотек времени выполнения C++ поверх него. Это предел оптимизаций уровня IL.


Среда выполнения

Давайте посмотрим, где мы находимся теперь с конфигурацией CoreRT по умолчанию:

4,7 МБ. Файл пока самый маленький, но этого недостаточно.


Умеренная экономия размера в CoreRT

Сейчас мы на уровне 4,3 МБ.


Включение сильной экономии в CoreRT

Я сгруппировал еще несколько вариантов компиляции в режим “сильной экономии”. Режим удаляет поддержку возможностей, важных для многих приложений, но не для нашей змейки. Мы удаляем:

Мы достигли 3,0 МБ, это 5% от начального размера, но у CoreRT есть еще один трюк.


Отключение рефлексии

Сейчас мы на уровне 1,2 МБ. Оверхед на рефлексию довольно значителен.


Пачкаем руки

Как мы уже видели ранее, CoreRT — это набор библиотек времени выполнения в сочетании с опережающим компилятором. Что делать, если мы заменим библиотеки времени выполнения с минимальным переопределением? Мы решили не использовать сборщик мусора, и это делает работу намного более выполнимой. Начнём с простого:

Мы просто переопределили Thread.Sleep и Environment.TickCount64 (для Windows), избегая всех зависимостей от существующей библиотеки времени выполнения. Делаем то же самое для подмножества System.Console , используемого игрой:

Пересоберём игру с заменой фреймворка:

Неудивительно, что это не слишком эффективно. Заменяемые API уже относительно легки, переписывание только добавляет пару килобайт, о которых не стоит упоминать. Но это важная ступенька к последнему шагу нашего путешествия.

Замена библиотек среды выполнения

Оставшиеся 1,2 МБ кода и данных в игре — это поддержка вещей, которые мы не видим, но они есть, они готовы, если нам понадобятся. Есть сборщик мусора, поддержка обработки исключений, код для форматирования и печати трассировок стека на консоль, когда происходит необработанное исключение, и многие другие вещи под капотом.

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

/noconfig , /nostdlib , и /runtimemetadataversion — волшебные параметры, необходимыми для компиляции чего-то, определяющего System.Object . Я выбрал расширение .ilexe , потому что .exe мы используем для готового продукта.

Перестроим IL с добавленным кодом и повторно запустим ILC.

Теперь у нас есть zerosnake.obj — стандартный объектный файл, который ничем не отличается от объектных файлов, создаваемых другими нативными компиляторами, такими как C или C++. Последний шаг — связать его. Воспользуемся link.exe , он должен быть в “x64 Native Tools Command Prompt”. Возможно, вам потребуется установить средства разработки C/C++ в Visual Studio.

Имя символа __managed__Main является контрактом с компилятором — это имя управляемой точки входа программы, созданной ILC. Но команда не работает:

Некоторые из этих символов кажутся знакомыми: компоновщик не знает, где искать вызываемые API Windows. Добавим библиотеки для них:

Выглядит лучше, всего 4 неразрешенных символа:

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

После перестроения исходного кода с этими изменениями и повторного запуска ILC, связывание, наконец, будет успешным. Мы сейчас на 27 килобайтах. Игра работает!


Возня с линкером

Оставшиеся килобайты можно получить с помощью трюков, которые используют разработчики нативного кода, чтобы уменьшить свои приложения. Мы собираемся:

  • Отключить инкрементное связывание.
  • Обрезать информацию о релокации.
  • Объединить похожие разделы внутри исполняемого файла.
  • Установить внутреннее выравнивание в небольшое значение

8176 байт! Игра все еще работает и, что интересно, она полностью отлаживаема. Вы можете отключить оптимизацию в ILC, чтобы сделать исполняемый файл еще более отладочным: просто удалите аргумент --Os .


Ещё меньше?

Исполняемый файл ещё содержит несущественные данные — компилятор ILC просто не предоставляет параметры командной строки, отключающие их генерацию.

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

Поскольку у нас нет сборщика мусора, эти данные не нужны. Другие среды выполнения — например Mono — используют консервативный сборщик, не требующий этих данных. Он просто предполагает, что любая часть стека и регистров процессора может быть ссылкой GC. Консервативный сборщик торгует производительностью GC ради экономии размера. Точный сборщик CoreRT также может работать в консервативном режиме, но он еще не подключен. Это потенциальное будущее дополнение, которое мы могли бы использовать, чтобы сделать программу ещё меньше. Может, однажды мы сможем сделать упрощенную версию нашей игры в 512 байт загрузочного сектора. А до тех пор — счастливого кода!

Читайте также: