Как сделать спидометр в unity

Обновлено: 05.07.2024

Продолжаем делать наш Unity for dummies платформер.

Полные версии кода будут находиться в конце поста.

Если вы не в курсе, как работают хуки жизненного цикла в Unity, вы можете ознакомиться с данной статьёй.

Затем выбираем наш объект Player слева, в меню иерархии, и закрепляем инспектор (меню справа), нажав на замок в верхнем правом углу.

Пока закрываем все ненужные компоненты (Box Collider 2D, etc), нажимая на стрелочку у каждого из них.

Теперь перетаскиваем наш скрипт в инспектор, и он прикрепляется к объекту Player (если вы не выполнили предыдщуий пункт с закрепением меню, то вы этого сделать не сможете).

Если зайти в Edit => Project Settings => Input Manager, то мы можём увидеть настройки управления. Например, прыжок (Jump) назначен на пробел, в то время, как движение по горизонтали назначено на a, d, ←,→.

Запомним это для того, чтобы затем использовать в коде (названия инпутов Jump, Horizontal).

Пора покодить. Два раза нажимаем на наш скрипт PlayerBehaviour, и Unity отдаст его в руки Visual Studio.

Честно, данную IDE я не люблю. Потому я открываю его в VScode (а вы хоть в VIMе пишите - это ваш выбор).

Я не буду часто использовать try/catch в этом коде, но вам очень советую - сильно экономит время.

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

Мне не нравится, что персонажа переворачивает. Исправим.

Заходим в инспектор, открываем Rigidbody2D и ставим галочку на Freeze Rotation Z.

Жить можно, но есть проблема - камера не двигается за персонажем.

Есть два основных способа научить камеру двигаться за персонажем.

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

2. Задать движение камеры за персонажем програмно.

Создаём скрипт CameraBehaviour, и привязываем его к объекту Main Camera (добавляем через инспектор).

Открываем наш новый скрипт, и начинаем кодить (да, мне на работе не хватает, продолжаю и после).

Фиксируем объект камеры на замок в инспекторе, и перетаскиваем наш объект Player в GameObject.

Теперь камера двигается за игроком.

Однако камера постоянно вылезает за пределы уровня, показывая синий фон.

Я не уверен, что моё решение правильное. Буду рад, если кто-нибудь поделится своими соображениями на данный счёт.

Если у камеры пропала рамка (у меня, внезапно, случилась такая оказия - потратил аж 2 минуты на решение проблемы), надо зайти в Gizmos и отметить чекбокс на камере.

Добавляем в наш скрипт CameraBehaviour следующий код:

[Header("Camera position restrictions")] public float minY; public float maxY; public float minX; public float maxX;

Двигаем камеру, и снимаем наши измерения ее положений.

На скрине ниже камера стоит в левом нижнем углу сцены.

Исходя из поля Position, я выбираю минимум по Х = -12, по Y = -0.5 (числа округлены их -12.09 и -0.84) соответсвенно.

Проставляем снятые позиции для камеры (мои и ваши позиции будут отличаться).

Теперь обновим метод UpdateCameraPosition в скрипте CameraBehaviour

Mathf.Clamp принимает первым аргументом позицию объекта, за которым следует игрок, вторым и третим аргументами минимум и максимум - этими значениями метод будет ограничивать число, которые по итогу получит камера в качестве своей координаты.

Отлично, камера перестала "гулять". Работаем дальше.

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

Выбираем наш Foreground, и создаём новый слой 'Ground' в инспекторе.

Снова тыкаем на Foreground, и выбираем в поле Layer наш только что созданный слой.

Переходим к коду.

Добавим в PlayerBehaviour такую строчку.

Теперь в объекте Player мы можем выбрать наш свежесозданный слой.

Обновляем наш PlayerBehaviour. Добавим коллайдер (rigidBody мы создавали ранее).

Теперь мы можем обновить обработку перемещения персонажа в методе updatePlayerPosition

Тут я вспомнил, что забыл глянуть, как "наделся" Box Collider на персонажа. Кажется, все ок - линии идут ровно по персонажу (жёлтая рамка). Если что, всегда можно ткнуть на Edit Collider и подтянуть его.

Летать мы разучились, а по платформе больше не скользим. Победа!

  • Из-за слоя Ground персонаж может прыгать от стенок. Не знаю, как это можно решить.
  • Является ли ограничение движения камеры, которое я написал, отимальным.
  • Иногда персонаж застревает на месте. Такое ощущение, что коллайдер видит какой то микропиксель, и персонаж застревает на нём.

Я не уверен, что моё решение правильное. Буду рад, если кто-нибудь поделится своими соображениями на данный счёт

Привет.
Я, конечно, дохуя вовремя, когда у тебя уже пять статей и рефакторинг, но вот щас иду за тобой пока вот на этом месте.
Короче, в ассет-сторе есть проект 2D Game Kit от разрабов движка. Там движение камеры сделано буквально следующим образом, если помню (давно открывал). Уровень завёрнут в коллайдер, ещё один коллайдер на камере. Соответственно, когда она о него стукается, то расслабляется и не двигается. И ещё там угарный камера-лаг стоит, чтоб камера не жёстко следовала за персонажем, а как бы за верёвочку.

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

Надо разобраться куда исчезает. Самое простое, поставить на паузу, перейти из окна Game в Scene, и просто посмотреть. А потом уже делать выводы.

Данный скрипт может реализовать любой вид транспорта, например автомобиль. Также здесь присутствует механическая анимация корпуса машины при разгоне и торможении. Колёса полностью работают и вращаются в нужном направлении движения автомобиля. Все параметры настраиваются: скорость машины, угол наклона салона и т.д.

Для реализации такого автомобиля нужно не только разместить этот скрипт на автомобиле, но и присвоить ему физические свойства: Rigidbody и Collider.
Остальные колёса, корпус и свет являются дочерними объектами автомобиля.

Добавить комментарий Отменить ответ

Мы - Wow Games,
команда, которая разрабатывает игры, а также приложения, помогающие Вам делать свои игры. Мы поможем, если у Вас возникли проблемы, и мы всегда рады новым участникам в нашей команде. Не бойтесь задавать вопросы, мы всегда на них ответим.

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

Урок по созданию простой машинки в среде Unity при помощи компонента WheelCollider. Описаны базовые настройки этого компонента. Для понимания урока необходимы базовые знания среды Unity.

08 | Простая машинка в Unity

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

    carRoot — контейнер для всех элементов машины (геометрия, свет, камеры, объекты для скриптов)
    car — контейнер для объектов именно машины,
    physic — контейнер для физических моделей колес,
    graphic — графические объекты.

01 | Простая машинка в Unity

2. Добавим в carRoot камеру и закинем на нее стандартный скрипт SmoothFollow, однако на 32 строке добавим или внешнюю переменную angle, или просто добавим поворот на 90 градусов, так как стандартный скрипт заставляет камеру быть сбоку от объекта :

02 | Простая машинка в Unity

3. в car добавляем компонент RigidBody, его масса — это масса корпуса машины, она будет влиять на устойчивость и на то, насколько сильно он прижимает колеса.

Для того чтобы на поворотах нас не сильно заносило, и при падении машина возвращалась в правильное положение, а не переворачивалась, нам потребуется два изменения — компонент ConstantForce в car, который будет прижимать машину на поворотах, кроме того, переместим центр массы машины вниз, добавив на нее скрипт carControl с кодом вроде этого:

03 | Простая машинка в Unity

4. В physic создаем пустой объект body с компонентом CapsuleCollider — это будет простой корпус машины, обтекаемый и не дающий застревать в стенках.

04 | Простая машинка в Unity

    Center — расположение колеса,
    Radius — радиус колеса,
    Suspension Distance — длинна пружин подвески.

Suspension Spring : Spring — сила пружины подвески, чем выше тем сильнее пружинит,
Suspension Spring : Damper — сила амортизатора, делает более плавным движение пружины.

06 | Простая машинка в Unity

Теперь добавим в объект wheel_BL простой цилиндрический меш, чтобы так сказать, иметь отладочную версию, впрочем, можно ограничится тем, что Unity нам и так предоставляет.

05 | Простая машинка в Unity

6. Раскопируем наше колесо до нужного числа, например, 4 — в принципе, машинка уже готова.

07 | Простая машинка в Unity

Теперь нам нужно только заставить колеса вращаться с ускорением по нажатию клавиш и поворачиваться, что можно сделать например так :

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

WheelColider – это компонент Unity3D, базирующийся на функционале физического движка PhysX, созданный специально, чтобы симулировать поведение автомобилей.

Множество игр базируются на физике автомобилей, например серия игр GTA или NFS. Так же, во многих играх транспорт является важным добавлением игровой механики – серия игр Battlefield, например. И, естественно, многие разработчики хотят добавить физику автомобилей в свой проект. Как раз для этого созданы WheelCollider’ы. Казалось бы, что может пойти нет так?

С самых первых версий Unity3D разработчики ведут неравный бой с WheelCollider’ами. Изначально проблема состояла из двух факторов:

– С одной стороны, WheelCollider’ы устроены очень примитивно, базовый функционал в Unity3D доступен ограничено.

– С другой стороны, на деле, кроме колеса и подвески нужно еще много чего написать. Объем работ, нередко, невероятно огромен.

Базовые проблемы – машина обладает низкой стабильностью поведения. В первую очередь – постоянно переворачивается. В этой статье я собрал коллекцию базовых техник, необходимых, чтобы решить проблему переворотов.

Эта статья состоит из нескольких частей:

– Несколько способов\методов\лучших практик, позволяющих сделать поведение машины на WheelCollider’ах более-менее приемлемым.

– Сборка машинки на основе очень кривой модели.

Перевод: Создание простого скелета

  1. Сначала, добавьте GameObject, который будет служить базой автомобиля. Чтобы сделать это, нажмите GameObject >CreateEmpty. Смените имя GameObject’а на car_root.
  2. Добавьте компонент Rigidbody на car_root. Стандартное значение массы в 1 кг слишком легкое для стандартных настроек подвески; установите массу на 1500 кг.
  3. Далее, создаем Collider автомобиля. GameObject >3D Object >Cube. Расположите куб под car_root в иерархии. Сбросьте параметры компонента Transform на 0 чтобы идеально выровнять куб в локальном пространстве. Автомобиль сориентирован параллельно оси Z (Z+ это направление вперед), поэтому меняем параметр ZScale на значение 3.
  4. Добавьте колеса к базе автомобиля. Выберите car_root и кликните по нему правой клавишей, далее CreateEmptyChild. Поменяйте название на wheels. Сбросьте параметры Transform на этом объекте. Этот GameObject не обязателен, но позже он поможет для настройки и отладки.
  5. Чтобы создать первое колесо, выберите wheels GameObject, правая клавиша >CreateEmpty, назовите новый объект frontLeft. Сбросьте Transform, а потом установите координаты: X на –1, Y на 0, и Z to Чтобы добавить колайдер, в меню инспектора нажмите Addcomponent >Physics >WheelCollider.
  6. Продублируйте GameObject frontLeft (правая клавиша >Duplicate). Измените координатыX c -1 на 1. Смените имя объекта на frontRight.
  7. Выберите frontLeftand frontRight GameObject’ы. Продублируйте их. Измените координатыZ на обоих GameObject’ах на –1. Измените имена на rearLeft и rearRight.
  8. Наконец, выберите car_root приподнимите его над поверхностью земли.

У вас должно получится что-то типа этого:


Чтобы машиной можно было управлять, вам нужно написать контроллер для неё:

У вас может быть до 20 колес на одной машине. Далее, добавим колеса. Как видите, Wheel Collider не добавляет визуальную часть колеса, поэтому нужно еще чуть-чуть кода.

Вам нужна геометрия колеса. Вы можете сделать простое колесо с помощью цилиндров. Есть несколько способов добавить визуальную часть колеса: добавить визуальную часть в параметры скрипта или написать скрипт, который будет автоматически находить и присваивать визуальную часть. Мы воспользуемся вторым вариантом. Добавьте визуальную часть колес под GameObject’ы Wheel Collider’ов.

Далее, изменяем скрипт SimpleCarController:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[System.Serializable]
public class AxleInfo <
public WheelCollider leftWheel;
public WheelCollider rightWheel;
public bool motor;
public bool steering;
>

public class SimpleCarController : MonoBehaviour <
public List axleInfos;
public float maxMotorTorque;
public float maxSteeringAngle;

  • Нужно проверить настройки инпута. Есть небольшой, но реальный шанс, что инпут обнулился при создании проекта. Edit > Project Settings… > Input. Конкретно нас интересуют оси Horizontal и Vertical, должно быть, как на картинки снизу.


  • Колеса слишком высоко, по итогу колеса не касаются земли > сдвинуть колеса по Y координатам на 0.5 юнита ниже (т.е. Y = -0.5)
  • Не выставлены значения в SimpleCarController > значение maxMotorTorque = 400

Лучшие практики, устранение проблем

1. Колеса смотрят непонятно куда

В двух словах нужно использовать пустой GameObject как базу для колеса, а затем саму модель нужно повернуть на 90 градусов по Z. Не забудьте присвоить базу колеса в SimpleCarController. В реальной ситуации колесо всегда состоит из нескольких моделей, так что изменения иерархии не избежать. Далее эта часть будет усложнятся – будем добавлять тормозные диски и суппорта.

2. Машину трясет при наборе скорости, Машина переворачивается – как увеличить стабильность?

Рассчитываем сжатие подвески в процентах слева и справа

-> сравниваем сжатия (левое сжатие минус правое)

-> знак результата сравнения дает направление приложения силы стабилизации (минус или плюс)

-> домнажаем то, что получилось на мощность стабилизатора

-> присваиваем в центр колеса.

Так же, есть смысл корректировать точку присваивания силы в соответствии с ForceAppPointDistance.

3. Когда автомобиль поворачивает, все колеса идут по разным траекториям.

Аккерман. (на русском нет статьи на вики, тем не менее). Для того, чтобы автомобиль не заносило (а в нашем случае – еще и не переворачивало), нужно, чтобы колеса рулевого управления поворачивали в соответствии с геометрией рулевого управления Аккермана. К сожалению, WheelCollider’ы устроены так, что при определенных углах проскальзывания колеса сила стремится к бесконечности – в этот момент машина пытается перевернутся. Чтобы снизить шанс переворота, нужно написать симуляцию Аккермана. ackermanSteering = 0 означает, что колеса поворачивают параллельно, 1 означает, что Аккерман присваивается в полной мере, в соответствии с положением колес\осей относительно друг друга.


4. Настройка частоты обновления колайдеров колеса

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

[System.Serializable]
public class AxleInfo
<
public WheelCollider leftWheel;
public GameObject leftWheelVisuals;
private bool leftGrounded = false;
private float travelL = 0f;
private float leftAckermanCorrectionAngle = 0;

public WheelCollider rightWheel;
public GameObject rightWheelVisuals;
private bool rightGrounded = false;
private float travelR = 0f;
private float rightAckermanCorrectionAngle = 0;

public bool motor;
public bool steering;

public float Antiroll = 10000;
private float AntrollForce = 0;

public float ackermanSteering = 1f;

public void ApplyLocalPositionToVisuals()
<
//left wheel
if (leftWheelVisuals == null)
<
return;
>
Vector3 position;
Quaternion rotation;
leftWheel.GetWorldPose(out position, out rotation);

leftWheelVisuals.transform.position = position;
leftWheelVisuals.transform.rotation = rotation;

//right wheel
if (rightWheelVisuals == null)
<
return;
>

rightWheel.GetWorldPose(out position, out rotation);

rightWheelVisuals.transform.position = position;
rightWheelVisuals.transform.rotation = rotation;
>
public void CalculateAndApplyAntiRollForce(Rigidbody theBody)
<
WheelHit hit;

leftGrounded = leftWheel.GetGroundHit(out hit);
if (leftGrounded)
travelL = (-leftWheel.transform.InverseTransformPoint(hit.point).y – leftWheel.radius) / leftWheel.suspensionDistance;
else
travelL = 1f;

rightGrounded = rightWheel.GetGroundHit(out hit);
if (rightGrounded)
travelR = (-rightWheel.transform.InverseTransformPoint(hit.point).y – rightWheel.radius) / rightWheel.suspensionDistance;
else
travelR = 1f;

AntrollForce = (travelL – travelR) * Antiroll;

if (leftGrounded)
theBody.AddForceAtPosition(leftWheel.transform.up * -AntrollForce, leftWheel.transform.position);
if (rightGrounded)
theBody.AddForceAtPosition(rightWheel.transform.up * AntrollForce, rightWheel.transform.position);

float angle = maxSteerAngle * input;
//ackerman implementation
float turnRadius = Mathf.Abs(wheelBaseLength * Mathf.Tan(Mathf.Deg2Rad * (90 – Mathf.Abs(angle))));
//38.363
if (input != 0)
<
//right wheel
if (angle > 0)

rightAckermanCorrectionAngle = Mathf.Rad2Deg * Mathf.Atan(wheelBaseLength / (turnRadius – wheelBaseWidth / 2f));
rightAckermanCorrectionAngle = (rightAckermanCorrectionAngle – Mathf.Abs(angle)) * ackermanSteering + (Mathf.Abs(angle));
rightAckermanCorrectionAngle = Mathf.Sign(angle) * rightAckermanCorrectionAngle;

>
else

rightAckermanCorrectionAngle = Mathf.Rad2Deg * Mathf.Atan(wheelBaseLength / (turnRadius + wheelBaseWidth / 2f));
rightAckermanCorrectionAngle = (rightAckermanCorrectionAngle – Mathf.Abs(angle)) * ackermanSteering + (Mathf.Abs(angle));
rightAckermanCorrectionAngle = Mathf.Sign(angle) * rightAckermanCorrectionAngle;

>

//left wheel
if (angle > 0)
leftAckermanCorrectionAngle = Mathf.Rad2Deg * Mathf.Atan(wheelBaseLength / (turnRadius + wheelBaseWidth / 2f));
leftAckermanCorrectionAngle = (leftAckermanCorrectionAngle – Mathf.Abs(angle)) * ackermanSteering + (Mathf.Abs(angle));
leftAckermanCorrectionAngle = Mathf.Sign(angle) * leftAckermanCorrectionAngle;
>
else
leftAckermanCorrectionAngle = Mathf.Rad2Deg * Mathf.Atan(wheelBaseLength / (turnRadius – wheelBaseWidth / 2f));
leftAckermanCorrectionAngle = (leftAckermanCorrectionAngle – Mathf.Abs(angle)) * ackermanSteering + (Mathf.Abs(angle));
leftAckermanCorrectionAngle = Mathf.Sign(angle) * leftAckermanCorrectionAngle;
>

>
else
<
rightAckermanCorrectionAngle = 0f;
leftAckermanCorrectionAngle = 0f;
>
leftWheel.steerAngle = leftAckermanCorrectionAngle;
rightWheel.steerAngle = rightAckermanCorrectionAngle;

>
>

private Rigidbody body;
private void Start()
<
body = GetComponent ();

for (int a = 0; a
<
axleInfos[a].leftWheel.ConfigureVehicleSubsteps(5, 12, 15);
axleInfos[a].rightWheel.ConfigureVehicleSubsteps(5, 12, 15);
>
>

public void FixedUpdate()
<
float motor = maxMotorTorque * Input.GetAxis(“Vertical”);

foreach (AxleInfo axleInfo in axleInfos)
<
if (axleInfo.steering)
<
axleInfo.CalculateAndApplySteering(Input.GetAxis(“Horizontal”), maxSteeringAngle, axleInfos);
>
if (axleInfo.motor)
<
axleInfo.leftWheel.motorTorque = motor;
axleInfo.rightWheel.motorTorque = motor;
>
axleInfo.ApplyLocalPositionToVisuals();
axleInfo.CalculateAndApplyAntiRollForce(body);
>
>
>

1. Для начала нужна модель автомобиля. В общем случае, есть 3 варианта где её достать: заказать у специалиста по игровым 3D моделям, купить/скачать с Asset store, скачать с стороннего сайта.

2. Создайте папку Models в ассетах игры. Распакуйте архив, и добавьте содержимое в папку Models

3. Зайдите в папку и перетащите файл “r34” на сцену. Должно получится так:

5. Под объектом r34 нужно создать пустой объект, назвать его Wheels, убедится, что этот объект находится на координатах 0.

6. В Scene view кликаем на колеса и диски – перетаскиваем их под объект Wheels

7. Внимание! Кликаем на колесо, смотрим координаты. Колесо, вроде, находится на дальней стороне автомобиля. И, вроде, гизмо контроля положения в его центре. А вот координаты почему-то на нуле. Это нормально – реальный центр колеса находится в центре автомобиля. Чтобы решить эту проблему создаем 3 пустых объекта на каждое колесо – один для WheelCollider’а, второй для визуальной части колеса, третий для калиперов. Далее, чтобы быстрее\проще их разместить можно воспользоватся изометрическим видом. Для этого кликните на одну из осей в правом верхнем углу Scene View. Чтобы вернутся в вид перспективы – кликните на сам центральный белый кубик. Координаты центров колес: FR(0.78, 0.32399, 1.399); FL(-0.78, 0.32399, 1.399); RL(-0.78, 0.32399, -1.26), RR(0.78, 0.32399, -1.26).

8. Переименовываем колеса в соответствии с иерархией, использованной в начале статьи: корневой объект называем в соответствии с положением (например FR_Wheel это front-right wheel, переднее правое колесо). Копируем, добавляем Visual (например, FR_WheelVisual). Добавляем под базовый объект покрышки, диски и тормозные диски. Называем покрышки Tire, тормозные диски называем BrakeDisc. Для тормозных скоб (калиперов) создаем копии базового объекта, называем в соответствии с положение – FR_Caliper и оставляем их на том же уровне иерархии, что базовые объекты колеса, добавляем под них соответствующий калипер. Должно получится вот так:


10. Выделяем все объекты под Body. Добавляем компонент MeshCollider (на панеле инспектора AddComponent -> MeshCollider) и жмем галочку Convex. Должно получится так:

В идеале геометрия, используемая колайдерами\физикой должна быть создано отдельно, с помощью специального плагина. Но, в этом уроке мы используем то, что у нас есть.

11. На коренной объект (r34) добавляем скрипт, контролирующий автомобиль.

12. На пустые объекты XX_Wheel добавляем WheelCollider’ы

Повторяем операцию с объектом Wheels, новый слой будет называться Wheel.

Далее Edit -> Project Settings… -> Physics

В матрице столкновений отключаем взаимодействие слоев Car и Wheel, должно выглядеть так:


И выставляем в Rigidbody Mass = 1500.

14. Выставляем параметры WheelCollider’ов: Radius = 0.315; ForceAppPointDistance = 0.315; TargetPosition = 0;

15. Корректируем управляющий скрипт, для работы с калиперами

Причина в том, что изначальная модель вырезана с небольшим отрицательным развалом колес. Поправляем модельки калиперов и самого колеса, на левой стороне ставим RotationZ = 4.5; на правой RotationZ = -4.5;

Восьмерка хоть и пропала, но колесо дергает вверх-вниз. Чтобы как-то сгладить ситуацию нужно подвинуть визуальные части колеса немного ниже, до Y = -0.269.

Так же, хочу обратить ваше внимание, что подобного рода проблемы возникают всегда, вне зависимости от качества базовых моделей\ассетов. Если вы хотите, чтобы Ваша система физики автомобиля была жизнеспособна, нужно учитывать подобного рода проблемы.

17. Настройка посадки

Ставим на всех WheelCollider’ах позицию Y на 0.47, а SuspencionDistance на 0.2.

Да, много работы 🙂

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