Устал всегда создавать одни и те же сценарии, которые никогда не заканчиваются так, как я бы хотел, чтобы они были, я решил начать новый проект: InDepth. Хотя я не создаю настоящую игру, я создаю ее основные компоненты. В результате, когда я работаю над сценарием, у меня есть только одна цель: сделать этот конкретный компонент как можно лучше!

На прошлой неделе я просмотрел JUMPING, который вы можете прочитать здесь:



Сегодня мы поговорим о ДВИЖЕНИИ. Точнее горизонтальное движение, как в платформере. Хотя многие из приведенных здесь принципов можно адаптировать к другим жанрам, платформеры были в центре моего исследования.

TL; DR;

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

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

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

Используйте AnimationCurve.Evaluate (Time.time - timeAtKeyDown), чтобы получить скорость персонажа.

Понимание хорошего движения

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

Сейчас мы перейдем к некоторым фактическим параметрам, но я хотел упомянуть об этом, поскольку понимание почему не менее важно (если не более того!), Как и понимание как.

Нашему персонажу явно нужна определенная скорость. Но мы также должны учитывать, как он достигает этой скорости и с помощью какой функции, то есть кривой ускорения. Для гоночной игры, такой как Sonic the Hedgehog, длительное увеличение скорости может быть уместным, чтобы побудить игрока сохранять импульс. Мы также можем выбрать логарифмическое ускорение:

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

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

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

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

Я должен упомянуть, что у Стива Свинка есть книга по« ощущениям от игры » и что в главе 7 о показателях отклика гораздо более подробно рассказывается об этих кривых и связанных с ними эмоциях игроков. Я также нашел одно исследование, измеряющее влияние ускорения и замедления на восприятие игроков, которое утверждает следующее:

Учитывая эфирное время и прыжки

До сих пор мы говорили о движении, когда игрок находится на земле. Но что происходит, когда игрок поднимается в воздух? Лично я прекратил создавать контроллеры персонажей с помощью встроенной в Unity физики и решил просто использовать CharacterController.Move () для генерации движения игрока. Однако, если мы посмотрим, что на самом деле произойдет в случае прыжка, на ум приходят трение и сопротивление. Персонаж больше не генерирует постоянный импульс движения, бегая, и окружающий воздух будет оказывать сопротивление. По этой причине мы можем захотеть по-другому смоделировать поведение персонажей в воздухе. Рассмотрим, например, прыжок с разбега в отличие от прыжка вперед, стоя на месте:

Наконец, во многих играх используется довольно щадящее движение воздуха, позволяющее игроку увернуться, повернуть вспять или остановиться в воздухе, если он направляется, скажем, к шипам от стены. Это создает проблему, если мы также хотим уменьшить ускорение в воздухе. Подвижность воздуха существенно ниже, чем перенесенная с момента начала прыжка (как в предыдущем примере). Затем нам может понадобиться способ сбросить импульс в случае, если игрок меняет направление. Разницу между сбросом импульса вместо объединения кривых можно увидеть здесь:

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

Реализация

Поняв, что входит в движение, мы можем приступить к его реализации.

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

Затем мы проверяем соответствующие клавиши ввода для игрока. Эта проверка должна выполняться в функции Update (), а все вычисления физики должны выполняться в функции FixedUpdate (). Мне нравится иметь главный контроллер, который обрабатывает проверку ввода, вызывает соответствующие функции в сценарии перемещения и объединяет выходные данные сценария перемещения с другими возможными сценариями, такими как прыжки, для получения окончательного вектора перемещения. Примерно так:

private void FixedUpdate(){
        playerVelocity = Vector3.zero;
        // little bit of default gravity
        playerVelocity += defaultVelocity * Time.deltaTime;
        // all controllers are applied here...
        playerVelocity += jumpController.JumpUpdate();
        playerVelocity += moveController.MoveUpdate();

        masterController.Move(playerVelocity * Time.deltaTime);
    }

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

Как видите, у меня есть четыре функции: GroundMove, GroundDecelerate, AirControl и AirDecelerate. Они принимают параметр направления как int.

Эти функции служат хорошей опорой, в то время как точная реализация дает вам большую свободу творчества. Я не хочу навязывать вам свое решение, но хочу поделиться несколькими сбоями, с которыми я столкнулся!

  1. Возможно, вам понадобится способ определить максимальную скорость игрока в вашем скрипте. Вместо того, чтобы иметь отдельное значение, которое необходимо установить в инспекторе, рассмотрите возможность использования moveOptions.deceleration.Evalute (0) для его получения.
  2. Возможно, вам потребуется запомнить скорость последнего кадра, например. при переходе в прыжок. В моей реализации я использую логическое requestStoreMovement, которое, если оно истинно, в конце функции MoveUpdate () сохранит вектор скорости.
  3. Подумайте, что произойдет, если ваш персонаж еще не достиг конца кривой ускорения, но теперь ему нужно замедлить. Кривая замедления начнет замедляться с максимальной скорости. Фигово. Это можно решить, вместо этого вычислив разницу в замедлении от максимальной скорости, а затем используя это для обновления скорости игрока как таковой:
 float diff = 
 maxSpeed - moveOptions.deceleration.Evaluate(Time.time-timestamp);
 float m = storedMovement.x * direction - diff;
 if (m > 0){
        movement.x = m * directionPram;
        requestStoreMovement = true;
 }

Это в значительной степени подводит итог. Движение в играх - это намного больше, чем просто движение влево и вправо. Вооружившись этими соображениями по дизайну, вы можете приступить к созданию отличных систем движения.

Надеюсь, это может вас заинтересовать. Ваше здоровье!