lexpexkex (lexpexkex) wrote,
lexpexkex
lexpexkex

О интересных ошибках в процессе разработки клона Марио.

Итак, напишу о том, что меня сильней всего достало в процессе и что я пока ещё помню.

1. Ошибка копипастинга и самая тупая ошибка новичка.
Естественно, изучение SFML я начал с видеоуроков (дедушка старенький, у него клиповое мышление).

Там при анимации была использована строка
if (CurrentFrame > count) CurrentFrame = 0; //если пришли к третьему кадру - откидываемся назад.
Всё работало хорошо и красиво. Но, думаю, вы уже поняли в чём подвох.
Однако, когда я начал переносить это в класс анимаций, где использовался массив кадров(), у меня начались спонтанные вылеты. Причём они были довольно редкими, поэтому их было трудно отловить. Сообщение об ошибке о выходе за пределы вектора было, но мне тогда не хватило мозгов принять во внимание.
Почему так происходило и почему происходило редко и почему работало раньше?

Естественно, когда CurrentFrame == count, то он выходил за пределы массива и обращался ХЗ куда, что вызывало вылет.

Почему это происходило раз в 5 минут или реже? Потому что CurrentFrame это флоат, зависящий от времени, скорости анимации и тд. А так как время в игре дискретно, то такая ситуация, когда CurrentFrame == count возникала крайне редко. Он был или на сотую меньше или на тысячную больше, но точное его попадание было довольно редким явлением, что создавало вид случайных редких вылетов (я даже сменил версию SFML!). Простейшая и банальнейшая ошибка. Впоследствии допускалась не раз, но теперь я был более внимателен к такому типу ошибок и сообщениям винды при вылете.

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

2. Столкновения. С ними я промучился больше двух месяцев. Дело в том, что у меня у разных кадров разные размеры. Именно их я брал для просчёта столкновений, рассчитывая, что это даст возможность сделать героя более соответствующим картинке. Однако, я не понял самого принципа, который лежал в простой модели столкновений из уроков. Она исходила из того, что изначальное положение правильно и герой ни с чем не пересекается. И может пересечься только в случае движения. Но у меня высота спрайта в следующем кадре могла измениться. И внезапно оказывалось столкновение, которое хрен разрешишь (непонятно, зашёл ли игрок сбоку или упал сверху и куда его надо переместить). Например, получалось, что при подходе к стенке игрок мог быть вытеснен на самый её верх.
Когда я сделал ширину и высоту константными - всё заработало нормально, хотя изначально хотелось немного другого. Соответственно, был введён отдельный от размеров спрайта ColisionBox.
С этой проблемой я мучился ОЧЕНЬ долго. Чрезвычайно долго. Пиздец, как долго. Гораздо дольше, чем со всем проектом. Пока я не вырезал квадратики из бумажек, до меня так и не дошла причина такого поведения.

3. Дроп мимо. Началось всё с того, что стандартным методом нельзя было отловить однократное нажатие мыши, ибо там было только "мышь нажата" или "не нажата". В итоге я понял, что мне нужно отлавливать перепад между состояниями "не нажата" и "нажата". Это и будет событие клика. Всё прекрасно работало, пока я не начал это отлавливать в классе инвентаря. В итоге у меня получилась ситуация, когда я дропал итемы в ячейку(вот же она, подсвечена и активна), а игра считала, что я дропаю мимо и выбрасываю на землю.
Почему так происходило? Потому что каждая ячейка обрабатывалась отдельно и сам дроп (событие отпускания клавиши мыши) совершался, когда ячейка уже была обработана и ничего принять не могла. А иногда совпадало. Поэтому глюк плавал. Решением стало обработка событий мыши в отдельном классе один раз за игровой цикл. И не в инвентаре. Это сразу решило множество проблем. На будущее думаю стоит так поступать и с клавиатурой и с прочим управлением. Оно не должно изменяться в цикле разными функциями, только вначале или в конце.

4. Двойные крафтовые фабрики. Если крафтовые фабрики (это в игре костёр и верстак) расположены рядом с друг другом, и игрок пересекается с обоими, то всё вылетает, ибо происходит "гонка сигналов". Класс инвентаря получает данные от одной, но некоторые переменные ей выставляет другая фабрика и вылет. Решилось простым обнулением всего лишнего перед взаимодействием с классом инвентаря. Но было довольно неожиданным, да.

5. Подбор и выкидывание. Тут мне вообще трудно понять что толком произошло.
Кажется, что всё просто. если мы наступаем на ресурс, то он добавляется в инвентарь. Но если инвентарь полон, то он выкидывается и добавляется на карту. Вроде всё хорошо. Бегу с полным инвентарём и пинаю "цветок", он выбрасывается передо мной, я его снова хватаю, но инвентарь полон и он снова выбрасывается. Всё правильно. Но начинаются просто дикие тормоза, вплоть до тех пор, пока "физика" не отключается и все не проваливаются сквозь пол.
Удаление с карты происходит раз в цикл. Даже не с карты, а совсем с небольшого листа интерактивных объектов.
Чему тут особо тормозить? Но тормоза дикие.
В итоге перед тем, как подобрать, я просто пытаюсь добавить в инвентарь объект той же функцией, что и добавляю, но без самого добавления. И в зависимости от результатов уже либо подбираю, либо нет. Функция довольно большая. Но тормозов нет, всё ОК.
А вот отчего они были, я так и не понял. Ведь у меня 4ГГц, мать его, компьютер. И зацикленности не должно получаться, ведь удаление с карты происходит раз в игровой цикл. Но тормоза были дичайшие.

6. Падение. С размаху об землю.
В игре есть такая фишка. Живут и существуют все только в пределах экрана, вне экрана они не обновляются.
В итоге есть такой как бы глюк. Если высоко подпрыгнуть перед врагом так, чтобы земля под ним вышла за пределы экрана, то враг упадёт, ибо земля под ним перестанет существовать. И сам он вовсе не умрёт, а останется там висеть (и будет виден на миникарте), пока игрок к нему не спустится. Так, кстати, побеждается главный босс игры.
Но я отвлёкся. На первом уровне брат Марио Луиджи объясняет, как надо играть. И если его уронить, а потом снова вернуться на уровень, то произойдёт вылет.
Почему? Потому что Луиджи упал. И замер, набрав некислую скорость по dy где-то под полом. И когда мы снова загружаем уровень, игра переносит его на своё место. И... Он уже набрал достаточно большое ускорение и с размаха бьётся о землю! Больно! Вот только анимации боли и страданий у него нет. А унаследован он от класса, где всё это есть. И происходит обращение к несуществующей анимации с вылетом. Тут либо обнулять dy, либо банально добавить ему анимацию, что я и сделал. Оба варианта. Я торопился))

Как-то так.

Теперь о делах насущных.
У меня бегут года и тд и тп. И я никак не могу и дальше определиться с выбором языка. С++ неплох, но я явно не собираюсь "убирать за собой" память. На примере тех же тормозов из-за подбирания-выкидывания очевидно, что в случае проблем скорость С++ мне хрен поможет. Так что чего попроще бы.

И снова не могу определиться ни в том, чего учить, ни в том,чего хочу сделать.

Варианты:

Питон:
За:
Говорят, простой.
На него куча книг по реальным проблемам и приложениям. Вообще в книгах по питону пока в других языках обсуждаются шаблоны, в них обсуждается уже какие-то реальные кейсы, вроде OpenCV.
Дата сайенс и нейросети. Разработка подобного мне не грозит, а вот использование... Почему бы нет?
Есть рабочие места.

Чего бы хотел написать, как дело всей жизни на питоне:
Сейчас есть такая вещь, как openPose. Хотел бы получать из кадра фильма позу или даже анимацию и переводить её в формат bvh. Поидее, ключевые точки в зд даст мне сам готовый опенПоз и моя задача перевести его в bvh. Да, для этого нужно разобраться и в опенпоз и в bvh и как всё это воткнуть в блендер.
Почему? Потому что более чем уверен, что мир достаточно ленив и многие интересные проекты так и не выстрелили до той стадии, которой ими можно пользоваться в реале.
Это даст возможность снимать анимации из фильмов. Вместо студии мокапа. Какой-нибудь файтинг из фильмов с Ван Даммом и Джеки Чаном, например, неплохо бы смотрелся.

Второе дело всей жизни - прикрутить к мейкхуману распознавалку лиц и дёргать его крутилки морды лица, пока распознавалка не даст добро.
Фактически, решение этой задачи в общих чертах описано тут.
https://habr.com/company/yandex/blog/421353
Что забавно, как раз там используется морфированная рожа и тягаются ползунки, задача практически один в один.

Именно поэтому, кстати, я и уверен, что никто нихера делать в качестве инструментов ни с опенпоз ни с мейкхуманом не будет. Сделать рожи из фотки могут давно, но ни одного, даже коммерческого, редактора персонажей, которому можно скормить фотку и получить модель с похожим лицом, я не видел. Почему? А ХЗ.

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

С#:
Дело всей жизни: одна-две игры, чтобы не совсем стыдно уж. Дело осложняется тем, что для игрушки крайне желателен упомянутый в целях всей жизни для питона инструмент. Ибо без него совсем треш получится.
За:
Скриптовый язык для большинства игровых движков.
Привычный мне синтаксис + сахар.
Большая инфраструктура NET.
Разрабатывается большой корпорацией.

Против:
Разрабатывается большой корпорацией.
Большая конкуренция.
Не кроссплатформенен.

Да будет срач!
Subscribe

Recent Posts from This Journal

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

  • 39 comments

Recent Posts from This Journal