Мені вдалося здійснити те, що мені потрібно, насамперед за допомогою цього допису в блозі, що розкриває поверхню частину головоломки і придумав власні ідеї щодо руху гравця та камери.
Прив’язання програвача до поверхні об'єкта
Основна установка складається з великої сфери (світ) і меншої сфери (гравця), обох із прикріпленими до них сферичними колідерами.
Основна частина проведеної роботи полягала в таких двох методах:
private void UpdatePlayerTransform(Vector3 movementDirection)
{
RaycastHit hitInfo;
if (GetRaycastDownAtNewPosition(movementDirection, out hitInfo))
{
Quaternion targetRotation = Quaternion.FromToRotation(Vector3.up, hitInfo.normal);
Quaternion finalRotation = Quaternion.RotateTowards(transform.rotation, targetRotation, float.PositiveInfinity);
transform.rotation = finalRotation;
transform.position = hitInfo.point + hitInfo.normal * .5f;
}
}
private bool GetRaycastDownAtNewPosition(Vector3 movementDirection, out RaycastHit hitInfo)
{
Vector3 newPosition = transform.position;
Ray ray = new Ray(transform.position + movementDirection * Speed, -transform.up);
if (Physics.Raycast(ray, out hitInfo, float.PositiveInfinity, WorldLayerMask))
{
return true;
}
return false;
}
The Vector3 movementDirection
Параметр так само , як це звучить, напрямок ми будемо рухатися нашим гравцем в цьому кадрі, і обчислення цього вектора, а в кінцевому підсумку відносно простий в цьому прикладі, було трохи складно для мене , щоб з'ясувати , в першу чергу. Детальніше про це пізніше, але тільки майте на увазі, що це нормалізований вектор у напрямку руху гравця цього кадру.
Переступаючи, перше, що ми робимо, - це перевірити, чи промінь, що походить від гіпотетичної майбутньої позиції, спрямованої на вектор гравців вниз (-transform.up), потрапляє у світ за допомогою WorldLayerMask, що є загальнодоступною властивістю сценарію LayerMask. Якщо ви хочете більш складних зіткнень або декількох шарів, вам доведеться створити власну маску шару. Якщо радіомовлення вдало вдарить по чомусь, то HitInfo використовується для отримання нормальної та точки влучення для обчислення нової позиції та обертання гравця, який повинен бути прямо на об'єкті. Зсув позиції гравця може знадобитися залежно від розміру та походження предмета гравця, про який йде мова.
Нарешті, це справді лише перевірено і, ймовірно, добре працює лише на простих об'єктах, таких як сфери. Оскільки в дописі на блозі я базував своє рішення, напрошується, ви, швидше за все, захочете виконати кілька радіопередач і порівняти їх за вашою позицією та обертанням, щоб отримати набагато приємніший перехід при переміщенні по більш складній місцевості. Можуть бути й інші підводні камені, про які я до цього часу не думав.
Камера та рух
Після того, як гравець приставав до поверхні предмета, наступним завданням було вирішити рух. Я спочатку починав рух по відношенню до гравця, але я почав стикатися з проблемами на полюсах сфери, де напрямки несподівано змінилися, завдяки чому мій гравець швидко міняв напрям знову і знову, не даючи мені ніколи пройти полюси. Те, що я завершив, робив рух своїх гравців відносно камери.
Що добре працювало для моїх потреб, це мати камеру, яка суворо стежила за гравцем, виходячи виключно з позиції гравців. Як результат, навіть незважаючи на те, що камера технічно обертається, натискання вгору завжди переміщувало плеєр у верхній частині екрана, вниз донизу тощо, ліворуч та праворуч.
Для цього було виконано наступне на камері, де гравцем був цільовий об’єкт:
private void FixedUpdate()
{
// Calculate and set camera position
Vector3 desiredPosition = this.target.TransformPoint(0, this.height, -this.distance);
this.transform.position = Vector3.Lerp(this.transform.position, desiredPosition, Time.deltaTime * this.damping);
// Calculate and set camera rotation
Quaternion desiredRotation = Quaternion.LookRotation(this.target.position - this.transform.position, this.target.up);
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, desiredRotation, Time.deltaTime * this.rotationDamping);
}
Нарешті, щоб перемістити плеєр, ми застосували трансформацію основної камери так, що з нашими елементами управління вгору рухається вгору, вниз рухається вниз і т. Д. І саме тут ми називаємо UpdatePlayerTransform, який отримає наше становище прив’язане до світового об'єкта.
void Update ()
{
Vector3 movementDirection = Vector3.zero;
if (Input.GetAxisRaw("Vertical") > 0)
{
movementDirection += cameraTransform.up;
}
else if (Input.GetAxisRaw("Vertical") < 0)
{
movementDirection += -cameraTransform.up;
}
if (Input.GetAxisRaw("Horizontal") > 0)
{
movementDirection += cameraTransform.right;
}
else if (Input.GetAxisRaw("Horizontal") < 0)
{
movementDirection += -cameraTransform.right;
}
movementDirection.Normalize();
UpdatePlayerTransform(movementDirection);
}
Для реалізації більш цікавої камери, але елементи керування приблизно такі ж, як у нас, ви можете легко реалізувати камеру, яка не відображається, або просто інший манекенний об'єкт, щоб базувати рух, а потім використовувати більш цікаву камеру, щоб зробити що ви хочете, щоб гра виглядала так. Це дозволить приємно переходити камеру, коли ви обходите об'єкти, не порушуючи керування.