Беннетт Фодди раскрыл секрет механики молота в Getting Over It

Фундаментальный элемент механики игры Getting Over It with Bennett Foddy — это молот главного героя. Именно этот инструмент служит основным средством взаимодействия с миром: с его помощью персонаж перемещается, преодолевая горы и абстрактные нагромождения объектов. Недавно разработчик проекта решил приоткрыть завесу тайны и поделился техническими деталями реализации этой системы.


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

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

Популярность сообщества лучше всего иллюстрируется его топовыми постами. До недавнего времени лидерство удерживала публикация о нестандартном эффекте WebGL, позволяющем отслеживать положение окон браузера на рабочем столе. Эксперты в комментариях сошлись на том, что это результат синергии window.getScreenDetails() и localStorage, обеспечивающего синхронизацию данных между окнами, либо комбинация получения системных координат окна и событий storage.

Однако лидеры рейтинга сменились: на вершину поднялся вопрос реддитора о механике молота в Getting Over It. Неожиданно для всех в дискуссию вступил сам создатель игры, Беннетт Фодди.

Фодди известен как автор QWOP — проекта, где управление ногами бегуна превращалось в издевательски сложный процесс. Браузерная версия 2008 года обрела феноменальную популярность: к 2011 году сайт разработчика насчитал 30 миллионов посещений. Позже Фодди экспериментировал с похожими концепциями в CLOP (симулятор единорога) и GIRP (скалолазание), пока не довёл эту идею до абсолюта в Getting Over It, где игрок управляет обнажённым мужчиной по имени Диоген, запертым в котле.

В то время как ранние игры требовали филигранной работы с клавиатурой, Getting Over It полностью полагается на мышь или тачпад. Управление положением молота через мышь позволяет совершать резкие махи, но из-за высокой чувствительности и физической модели развитие мышечной памяти требует колоссального терпения.

Беннетт Фодди не просто дал совет — он выложил фрагмент исходного кода функции fixedupdate, подробно описав внутреннее устройство системы. По словам автора, он сам уже не помнит всех нюансов реализации, но суть такова: обратная кинематика рук не влияет на физику напрямую; молот приводится в движение вращательными и поступательными сочленениями, а всё управление базируется на принципах простого пропорционально-дифференциального регулятора.

Vector2 mw = (Vector2)fakeCursorRB.position;

//this value ranges between 0.1 and 0.4 mouseVelocityAverage = Mathf.Lerp(mouseVelocityAverage, Mathf.Max(0.1f * mouseInput.magnitude, 0.001f), 0.05f) + 0.005f;

//move fake cursor - using acceleration Vector2 newPosition = fakeCursorRB.position + mouseInput;//* mouseVelocityAverage;

//clamp to radius float distanceToPlayer = ((Vector2) transform.position - newPosition).magnitude; if (distanceToPlayer > 3.5f) { newPosition = (Vector2) transform.position + ((newPosition - (Vector2) transform.position).normalized * 3.5f); }

Vector2 tipDelta = (Vector2) tipRB.position - mw; Vector2 poleDir = (Vector2) (tipRB.position - hjRB.position).normalized; //hjRB is the hinge joint RB //a dot product is used to make the rotation dominate when the mouse is perpendicular to the pole dotProd = Vector2.Dot(poleDir, tipDelta.normalized); posDelta = tipDelta.magnitude * dotProd;

//move back to tip head newPosition += 0.5f tipDelta Mathf.Clamp(0.2f - Mathf.Min(mouseVelocityAverage,0.2f), 0, 0.2f);

fakeCursorRB.MovePosition (newPosition); fakeCursorRB.velocity = (newPosition - fakeCursorRB.position);

Vector2 mwDelta = (Vector2)hjRB.position-mw; Vector2 tDelta = hjRB.position - tipRB.position; float angleDelta = Vector2.SignedAngle(tDelta,mwDelta); //hingeJoint2D.angle no longer works accurately

//different behavior close vs far angleDelta = Mathf.Sign(angleDelta) Mathf.Max(Mathf.Abs(angleDelta/2f), Mathf.Abs(angleDelta angleDelta)); angleDelta *= Mathf.Clamp01 (Mathf.Abs (angleDelta) / angleEpsilon);

motor.motorSpeed = Mathf.Clamp( (angleDelta (3f) + (angleDelta - oldAngle) 0.00f) * Mathf.Pow(Mathf.Clamp01(mwDelta.magnitude/deadzone),2), -800f,800f); hj.motor = motor;

float speedFactor = 16f - Mathf.Max(sj.reactionTorque0.008f ,5f); //had to make this stronger, no idea why float axisBlend = Mathf.Pow(dotProd,4); slider.motorSpeed = Mathf.Clamp(-posDeltaMathf.Abs(posDelta) speedFactor axisBlend,-50f,50f); sj.motor = slider; oldAngle = angleDelta;

В игре не используется системный курсор: вместо него введено «фиктивное» тело fakeCursorRB, которое накапливает относительные движения мыши и ограничено радиусом в 3,5 единицы вокруг игрока. Это решение нивелирует влияние перемещения камеры на управление персонажем. Фодди также предусмотрел «мёртвую зону» в центре вращения, где чувствительность динамически регулируется, чтобы избежать резких рывков при малых движениях.

Интересно, что физика игры работает на более высоких частотах, чем стандартная частота обновления монитора. Фодди использовал FixedUpdate с активным continuous collision detection и дробными временными шагами, так как контроллер рассчитан на очень высокие скорости вращения и перемещения. Корневой объект персонажа перемещается, но его вращение жестко ограничено, иначе реактивный момент от молота сделал бы геймплей неуправляемым.

Рукоять молота — это набор физических тел, соединённых через fixed joint 2D для обеспечения минимальной гибкости. В то же время руки персонажа реализованы исключительно через обратную кинематику: они «прилипают» к молоту постфактум, не оказывая силового воздействия на физическую модель. Моторы вращения и скольжения постоянно стремятся привести молот к цели, заданной мышью, но благодаря физическому движку и столкновениям с окружением именно эти попытки «вытягивают» котел с персонажем вверх.

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

 

Источник

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