Гравитация вручную
Часть раздела Создание настоящих игр путешествия по Unity на Coddy. Урок 38 из 56.
CharacterController падает только тогда, когда скрипт заставляет его падать, а настоящее падение ускоряется: гравитация каждую секунду добавляет примерно 9.81 единицы в секунду к скорости падения. Поэтому скрипт хранит вертикальную скорость в поле, каждый кадр прибавляет к ней gravity * Time.deltaTime и перемещает контроллер на эту величину в том же вызове Move, что и при ходьбе:
public float gravity = -9.81f;
float verticalSpeed;
void Update()
{
if (controller.isGrounded && verticalSpeed < 0f)
{
verticalSpeed = -2f; // на земле: остановить падение, сохранить небольшое усилие вниз
}
verticalSpeed += gravity * Time.deltaTime;
Vector3 move = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical")) * speed;
move.y = verticalSpeed;
controller.Move(move * Time.deltaTime);
}Time.deltaTime используется дважды для разных задач: gravity * Time.deltaTime — это прирост скорости за этот кадр, а скорость, умноженная на Time.deltaTime, — это расстояние, пройденное за этот кадр. Скорость хранится в поле, потому что её значение должно сохраняться от кадра к кадру; локальная переменная каждый кадр снова начинала бы со значения 0. При падении из состояния покоя скорость контроллера составит -4.9 единицы в секунду через полсекунды и -9.81 через одну секунду.
Сброс важен не меньше, чем само падение. На полу Move останавливает контроллер, но ничто не останавливает рост значения в поле: без сброса оно продолжает расти, пока игрок стоит, и при следующем шаге с края игрок начнёт падать на полной скорости. Скорость сбрасывается до небольшого отрицательного числа, а не до 0, чтобы каждый Move по-прежнему прижимал контроллер к полу: при высокой частоте кадров толчок от гравитации за один кадр может быть меньше Min Move Distance, Move ничего не сделает, а isGrounded станет false. isGrounded считывается до вызова Move, поэтому его значение описывает результат Move за предыдущий кадр.
Задание
СреднеНыряльщик стоит на высокой башне, а стрелки передвигают его (это уже написано). Добавь ему гравитацию в Diver.cs. В Inspector задай gravity (-12) и maxFall (10), а в скрипте есть поле verticalSpeed.
- Каждый кадр
verticalSpeedувеличивается наgravityв секунду, и ныряльщик движется вниз на это значение в том же вызове Move, что и при ходьбе. - Воздух замедляет долгое падение: скорость падения ныряльщика никогда не превышает
maxFallединиц в секунду. - Когда контроллер стоит на земле и
verticalSpeedменьше 0, задайverticalSpeedзначение -1.
Нажми Play, сойди с башни, затем нажми Check.
Попробуйте сами
using UnityEngine;
public class Diver : MonoBehaviour
{
public float speed = 4f;
public float gravity = -12f;
public float maxFall = 10f;
CharacterController controller;
float verticalSpeed;
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update()
{
// Гравитация: сбрось verticalSpeed на земле, добавь гравитацию, ограничь скорость падения и запиши результат в move.y
Vector3 move = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical")) * speed;
controller.Move(move * Time.deltaTime);
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Создание настоящих игр
1Текст на экране
Холст и текстПокажем счётФорматирование чиселТаймер обратного отсчётаПовторение: спидометр4Сцены и уровни
Загрузить сценуПерезапустить уровеньСледующий уровеньСохранить между сценамиПовторение: выбор уровня7Управление временем
Пауза с timeScaleЗамедленное движениеНемасштабируемое времяПовторение: Bullet Time10Проект: 3D-платформер
ТрассаДвижущиеся платформы2Кнопки и экраны
Кнопки и onClickЛямбдыСвязи в InspectorВключение и выключение панелейШкалы здоровьяПовторение: магазин улучшений5Сохранение с помощью PlayerPrefs
Сохранение числаЗагрузка со значением по умолчаниюРекордСохранение настроекПовторение: монеты в банке8Контроллер персонажа
CharacterController.MoveГравитация вручнуюПрыжкиТолкаем предметыДвижение в направлении взглядаПовторение: двойной прыжок