Ответ на пост «Сегодня я стал догхантером»5
Пару дней назад чуть не стал догхантерлм
Еду по Тавриде, в районе Керчи там разрешённая 90, вдоль дороги поля, поля, поля!
Не далеко от отбойников пасётся стадо коз, пастух, собака, и все такое
И вот еду я свои 90, в правой полосе, никого не трогаю, вижу это стадо на изгибе дороги, вижу собаку, которая медленно но верно двигается к дороге, а смотрит в поле. Я собак люблю, и всегда думаю, что они умные, тем более пастушьи. Но на всякий случай скорость начал сбрасывать и сместился левее, и не отпуская взгляда с собаки вижу, что псина не глядя идёт на дорогу и выходит прямо передо мной, до нее метров 50, у меня в машине 2 детей, жена, холодильник с пивом, резкие маневры не рекомендованны, а псина всё идёт и идёт не глядя, уже на середине дороги.
Я сбрасываю скорость, принимаю уже правее, думал объехать, а в зеркало заднего вижу там летит торопыга, в левой полосе, быть фаршу, или если вдруг чего, он же и в меня прилетит.
Вообщем я сигналю, псина просыпается и щемится опять на обочину, и все это у меня буквально перед бампером. Я думал собью, виляю в право, торможе и передачей и тормозом, чуть не глохну. Псина стоит на обочине, виляет хвостом, лыбится
встает пастух, свистит, и псина срывается к нему задорно лая! и вот я думаю!
БИЛЯТЬ!!! ЭТО СУКА ТУПАЯ ЧУТЬ ФАРШЕМ НЕ СТАЛА!
Еблан с хлыстом видел же раньше что псина на дорогу ломится, Херли раньше не свистнул.
Тесаки польских янычар
Уставной тесак янычар саксонского курфюста Августа II Смелого очень красивое, необычное и редкое оружие. Всего было изготовлено около 770 образцов.
Мотивация11
Фирма на где-то 60 сотрудников. Посреди своего отпуска приходит сотрудник и сообщает руководству, что у него заканчивается завтра контракт и новый он подписывать не будет - уже нашел новое место работы. Это уже третий человек, который уходит в течение нескольких месяцев.
Начальство начало подозревать, что что-то не так и решило найти корень проблемы:
- Вот, ты Серега наверняка не на одно собеседование сходил, да?
- Да, я в 4 местах был и везде меня готовы были взять.
- А вот чем они все тебя мотивировали? Может там какие-то секреты есть?
- Деньгами, везде предлагали зарплату минимум в полтора раза выше, чем у нас.
- Да бог с ним с деньгами, а вот чем они реально работников привлекают? Какую мотивацию работникам предлагают? Наверняка есть какой-то секрет.
- ...
Как устроен Braid?
Многие играли в знаменитую инди-игру Braid и многие были впечатлены механикой возврата во времени. Для меня, как для программиста, это было особенно интересно, я решил попробовать повторить эту механику и вот что я узнал.
Для начала немного справки для тех, кто пропустил эту замечательную игру. Braid - инди-проект от американца Джонатана Блоу, вышедший в 2008 году и ставший хитом, купленным более 55 тысяч раз в течение первой недели после релиза. Основная фишка игры в Rewind механике, позволяющей развернуть время вспять и «отмотать игру» назад, после чего попробовать пройти уровень заново.
Все примеры (GIF) интерактивны в оригинальной версии статьи (ссылка будет в конце)
Начнём с простого
Сперва попробуем упростить себе задачу - представим, что вся наша игра сводится к управлению точкой в одномерном пространстве. С помощью W и S мы будем двигать точку вдоль вертикальной прямой, а справа от неё будем изображать график зависимости её положения от времени. Иконки на графике будут отмечать моменты во времени, когда мы нажимали на кнопку или отменяли действие уже нажатой кнопки.

Обычно перемещение предмета в простых играх делается с помощью специального таймера, каждый тик которого немного меняет положение предмета на несколько пикселей. Если это происходит 30 раз в секунду, то нам кажется, что объект плавно движется в нужном направлении. Это императивный подход.
Но иногда в приложениях используется другой подход - декларативный. Вместо того, чтобы определять, как именно будет меняться положение мяча каждые 1/30 секунды, мы можем описать, как будет зависеть положение мяча от текущего времени - создать функцию ball_position (t), где t - текущее время.
Как это сделать? Очень просто - используя таймлайн событий. Мы знаем, например, что последнее событие - нажатие на кнопку W (то есть вверх), мы знаем точное время и мы знаем положение мяча на момент нажатия на кнопку. Значит, мы без проблем можем вычислить текущее положение мяча.
Теперь нам не нужно хранить положение мяча вообще - оно будет высчитываться заново каждый раз, когда отрисовывается кадр. Обратите внимание, что теперь у положения мяча иногда появляется дробная часть - мы не можем точно знать, что рендеринг придется на 1/30 секунды. А ещё нажатие на обе кнопки (W и S) теперь приводит мяч в движение - в отличие от предыдущего примера, где кнопки отменяли друг друга.

Повернем время вспять
Теперь мы можем добавить ещё одно понятие - внутреннее время. Дело в том, что мы не можем поменять то, что возвращает нам функция now(), но нам необязательно передавать её результат в функцию нахождения положения мяча. Если мы заменим `now()` на `now() / 2`, то время в игре будет идти в два раза медленнее.
Но это ещё не всё - мы ведь хотим управлять временем с помощью клавиатуры. И не только замедлять или ускорять, но и поворачивать вспять. Мы хотим сделать так, чтобы внутреннее время зависело от внешнего и от нажатий на клавиатуру примерно таким образом:
Что-то напоминает, не правда ли? Ах да, это же почти точно такой же график, как тот, что мы строим для положения мяча. Внутреннее время зависит от внешнего так же, как и положение мяча зависит от внутреннего времени. Просто вместо кнопок W и S, игра реагирует на нажатие пробела.

Нажатие Space оборачивает время вспять
Получается каскад из функций - сначала из внешнего времени (времени системы) мы находим внутреннее время игры (то, что указано сверху в таймлайне) и только затем исходя из внутреннего времени игры мы находим положение мяча. И на первом и на втором этапе мы используем лог событий (нажатий на W, S или Space), чтобы понять, как именно время или положение мяча менялись с момента последнего события. Круто?
Добавим второе измерение
Пойдём чуть дальше и усложним задачу - добавим второе измерение. Теперь наш мяч будет двигаться не только вверх или вниз, но и влево / вправо. Заодно обновим таймлайн, и будем использовать глубину для отображения времени события.

Ускоримся
Важный элемент, которого не хватает в нашей игре - ускорение. Дело в том, что в играх-платформерах персонажи и объекты не движутся равномерно. Почти всегда они движутся с некоторым ускорением, то есть квадратично, например, когда падают. Обычно (в императивном подходе) это делается как-то так:
Но у нас нет переменных для текущей скорости или даже текущего положения - у нас есть только функция, которая возвращает нам положение мяча для определенного времени. Чтобы добавить в эту функцию ускорение, нам нужно вспомнить школьную математику, а именно равноускоренное движение.
Как вы можете заметить, кроме position, event теперь должен хранить ещё и velocity (скорость) - значит, нам нужна функция, которая посчитает скорость для заданного внутриигрового времени. В итоге у меня получилось что-то вроде этого:

Соберем платформер
Осталось дело за малым - собрать из всего этого платформер! Движение влево и вправо будет равномерным, а прыжок и падение равноускоренными. Заодно добавим платформы и специальное событие, обозначающее касание персонажем платформы.
Я не буду приводить здесь весь код, так как по большей части он не сильно отличается от кода любого другого платформера, который можно найти в любом другом гайде (а ещё потому что я особо не старался превратить это в платформер). Сразу покажу Вам результат:

Вот собственно и всё. Конечно, за пределами статьи остались очень сложные моменты - монстры, смерть персонажа, лазанье по лестницам, но я хотел рассказать именно о rewind-механике. Если вам понравилась эта статья - обязательно подпишитесь и прокомментируйте.