Программирование игр всегда было одним из моих интересов с тех пор, как я написал простую игру Pong! еще в колледже с помощью Processing. Но моя первая работа оказалась в веб-разработке, и с тех пор это все, чем я занимаюсь. Проникнуть в веб-разработку легче, чем в разработку игр (у меня нет формального образования в области компьютерных наук), и, следовательно, после двух лет работы в качестве члена общества я m все еще находится в веб-разработке.

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

Разобравшись, как настроить SFML for XCode, я вник в суть и начал программировать. Это были адские 10 дней, и вот некоторые вещи, которые, я думаю, стоит отметить, потому что они доставили мне неприятности. И всегда стоит помнить о вещах, которые доставляют вам неприятности.

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

Достаточно просто.

Заголовки и защита заголовка?

Одной из первых вещей, которые мне пришлось решить, было то, как структурировать файлы заголовков. Заголовочные файлы и вся концепция предварительных объявлений не существуют в Java и Javascript (два языка, которые я использовал в прошлом), поэтому работа с заголовочными файлами была для меня совершенно новым опытом, особенно когда дело касалось организации проекта. . Здесь я столкнулся с бинарным выбором (если есть еще способы сделать это, кто-нибудь дайте мне знать):

Сохраню ли я их вместе с исходным файлом, чтобы каждая пара сохранялась как единое целое? Или мне хранить все заголовки в одном месте?

Code::Blocks организует свои проекты, разделяя свои файлы на деревья source и header, а сама библиотека SFML имеет заголовки, хранящиеся в одной папке в иерархической структуре. Хотя кодирование в современных IDE стало проще, чем когда-либо (вы перемещаете файл, и IDE обновляет все сотни ссылок за вас!), я по-прежнему хотел, чтобы все мои заголовки находились в одном месте и на них можно было ссылаться из любой точки мира. одно корневое расположение. Поэтому я поместил их все в каталог header в корне моего проекта.

Еще одна вещь, которая меня сбила с толку, это охранники головы. Я понял, что это такое, и я понял, как их использовать, но я позволил IDE сделать работу по созданию охранников при создании новых файлов заголовков (охранники были названы в соответствии с путем к файлу внутри папки src; пример: MOVE_COMPONENT_GRAPHIC_H ), в результате чего после того, как я переместил и переименовал некоторые файлы, защита заголовков не обновлялась (среда IDE не такая умная), так что в итоге я получил два файла заголовков с одной и той же защитой.

И что произошло, когда я включил оба в свой main.cpp?

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

Я по-прежнему позволяю IDE генерировать для меня защиту (нет смысла в среде IDE, если она не выполняет тяжелую работу), но я всегда дважды проверяю, чтобы убедиться, что никакие другие файлы не имеют такой же защиты. Быстрый текстовый поиск по всему проекту помогает.

нан, нан, нан, нан, нан…

Сначала я не знал, что в SFML есть свои собственные классы Vector (я не использовал RTFM, просто перешел к коду; дети, не делайте этого. Всегда RTFM!), и поэтому пошел дальше и написал один из моих собственных. Класс 2D-векторов, в котором есть элементы x и y, а также обычные методы для векторных вычислений, включая метод нахождения величины вектора и метод его нормализации. Теперь вот как вы нормализуете вектор. Как видите, если величина равна нулю, вас ждут некоторые проблемы.

Теперь в Java деление на ноль выбрасывается как Exception. В NodeJS деление на ноль дает Бесконечность, но для C++ деление на ноль дает нан соответствующего типа (да, нан для двойного числа — это не тот же тип, что и нан для числа с плавающей запятой, точно так же, как 0 и 0.0 — разные типы). Я не знал, что это произойдет, и я забыл учесть векторы нулевой величины.

Итак, что случилось?

Ничего такого. Буквально ничего не произошло. Как и в случае, никакие вычисления не будут работать, потому что я вычисляю с помощью nan повсюду, а nan, вычисляемый с любым числом, дает вам nan. Мне потребовалось несколько распечаток значений, чтобы понять это, хотя задним числом это должно было быть смехотворно очевидным.

Перетащите

Еще одна идиотская вещь, которую я сделал, заключалась в написании функции перетаскивания. Вот первая версия этого.

void scionofbytes::apply_drag(scionofbytes::Mover& mover) {
    scionofbytes::Vec2D drag = mover.velocity.scale(-1);
    opposite_velocity.normalize();
    opposite_velocity.scale(scionofbytes::DRAG_COEFFICIENT);

    mover.velocity.subtract(drag);
};

Кто-нибудь видит, что я сделал неправильно здесь? Кто-нибудь?

Я подожду.

Хорошо, если вы еще не поняли, я вычел вектор сопротивления, когда должен был добавить его.

Видите ли, я уже вычислил силу сопротивления как вектор в направлении, противоположном вектору скорости. И, вычитая этот вектор вместо того, чтобы добавлять его к скорости, я просто увеличивал скорость.

Это похоже на вычитание отрицательного числа: на самом деле вы добавляете значение хода. Видеть?

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

Ваше здоровье!