код для управления персонажем на юнити 3д
Код для управления персонажем на юнити 3д
Нажимаем «Add component>>Physics>>Rigidbody» и «Add component>>Physics>>Capsule Collider». В «Capsule Collider» Выставляем размеры нашей капсулы что бы получилось как на картинке, слегка чуть больше модельки самой.
В «Rigidbody» ставим галочку «Use gravity». Раскрываем вкладку «Constraints» и ставим все 3 галочки на «Freeze Rotation». Это нужно для того что бы наш персонаж не проваливался сквозь землю, не падал на землю если вдруг окажется на неровности и тому подобное.
Программируем персонажа на перемещение.
Создадим c# скрипт «movePlayer».
200?’200px’:»+(this.scrollHeight+5)+’px’);»> using UnityEngine;
using System.Collections;
public class movePlayer : MonoBehaviour <
private GameObject player; //Переменна объекта персонажа с которым будем работать.
public static int speed = 6; //Скорость перемещения персонажа. Запись public static обозначает что мы сможем обращаться к этой переменной из любого скрипта
public static int _speed; //постоянная скорость перемещения персонажа
public int rotation = 250; //Скорость пповорота персонажа
public int jump = 3; //Высота прыжка
//Поворачиваем персонажа. Так как наша переменная x глобальна, из скрипта камеры в неё будем записывать длину на сколько сместился указатель мыши и по оси X и относительно этого будет повернут наш персонаж
Quaternion rotate = Quaternion.Euler (0,x,0); //Создаем новую переменную типа Quaternion для задавания угла поворота
player.transform.rotation = rotate; //Поворачиваем персонаж
200?’200px’:»+(this.scrollHeight+5)+’px’);»> codeusing UnityEngine;
using System.Collections;
private float x = 0.0f; //Угол поворота по Y?
private float y = 0.0f; //Уго поворота по X?
[AddComponentMenu(«Scripts/Mouse Orbit»)] //Добавляем в меню
public void Start() <
//переворачивам углы
Vector3 angles = transform.eulerAngles;
x = angles.y;
y = angles.x;
if(rigidbody)
rigidbody.freezeRotation = true; //Если камера столкнется с физ.объектомона остановиться
>
y = ClampAngle(y,yMinLimit, yMaxLimit); //Вызыв самописной функции для ограничения углов поврот
movePlayer.x = x;
//Повернуть камеру согласно поченым данным
Quaternion rotation = Quaternion.Euler(y, x, 0);
transform.rotation = rotation;
200?’200px’:»+(this.scrollHeight+5)+’px’);»> using UnityEngine;
using System.Collections;
public class AnimatePlayer : MonoBehaviour <
Управление персонажем, с помощью мыши в Unity
Стандартные Asset управления в Unity имею несколько скриптов, перемещение только с помощью клавиатуры и клавиатуры и мыши, но отсутствует скрипт перемещения с использованием мыши («Diablo-style»). Скрипты будет написаны на C#.
public class MouseCamera : MonoBehaviour <
// Позиция объекта Target
public Transform target;
// Слой(и) которые реагируют на клик
public LayerMask mask;
// Персонаж которым управляем
public MousePerson player;
// Вектор перемещения
private Vector3 direction;
// Информация о луче
RaycastHit hit;
void Update() <
if (Input.GetMouseButtonUp(0)) <
// Получаем направление луча
Ray ray = camera.ScreenPointToRay(Input.mousePosition);
// Кидаем луч бесконечной длинны и проверяем пересечение слоев
if (Physics.Raycast(ray, out hit, Mathf.Infinity, mask)) <
// Проверяем то, что вернулось и перемещаем туда наш Target
target.position = hit.point;
// Сообщаем персонажу о новом «задание»
player.GetTarget(target.position);
>
>
>
>
Скрипт проверяет пересекает ли место клика объект(ы) указанные в слое, перемещает в это место объект цели и «говорит» персонажу двигаться к этому месту.
Скрипт персонажа немного больше, но не сильно сложнее.
using UnityEngine;
public class MousePerson : MonoBehaviour <
// Персонаж
CharacterController player;
// Радиус в котором персонаж считает что он у цели
public float radiusNoClick = 3f;
// Координаты Target
public Vector3 target = Vector3.zero;
// Вектор перемещения
private Vector3 direction;
// Скорость поворота
public float speedRotation = 10f;
// Скорость передвижения
public float speedMove = 45f;
// Маркер персонажа, на месте или нет
private bool onPlace = true;
// Анимации
private Animation _animation;
// Состояния
enum CharacterState <
Idle = 0,
Walking = 1,
>
// Состояние
private CharacterState _characterState;
void Start() <
// Получаем анимации
_animation = GetComponent();
// Получаем персонажа
player = (CharacterController)gameObject.GetComponent(typeof(CharacterController));
>
// Поворачиваемся
Quaternion look = Quaternion.LookRotation(direction);
this.transform.rotation = Quaternion.Slerp(this.transform.rotation, look, Time.deltaTime * speedRotation);
// Двигаемся
player.Move(direction * Time.deltaTime * speedMove);
// Персонаж в движении
_characterState = CharacterState.Walking;
>
else
// Персонаж в состоянии «покоя»
_characterState = CharacterState.Idle;
if (_animation) <
// Включаем нужную анимацию в зависимости от состояния
if (_characterState == CharacterState.Walking)
_animation.Play(«walk», PlayMode.StopAll);
else if (_characterState == CharacterState.Idle)
_animation.Play(«idle», PlayMode.StopAll);
>
>
public void OnPlaceTrue() <
onPlace = true;
>
>
Метод GetTarget() принимает из скрипта MouseCamera позицию цели и проверяется не находится ли он около персонажа. Если все хорошо и цель далеко, персонаж начинает движение в сторону цели, путем вычислений проводящихся в Update(). Метод OnPlaceTrue() служит для указания персонажу, что он на месте. Он используется в небольшом триггере который размещается на объект Цели.
public class TriggerOnTarget : MonoBehaviour <
public MousePerson player;
void OnTriggerEnter(Collider onPlace) <
player.OnPlaceTrue();
>
>
При пересечении зоны триггера, сообщается что персонаж прибыл в место назначения.
В коллайдере необходимо указать что «он» триггер, установить радиус (зависит от размеров вашего персонажа) и указать в скрипте персонажа, от которого он зависит.
У персонажа в скрипте все настройки оставлены по умолчанию, и ничего дополнительного указывать нет необходимости.
На камере в скрипте необходимо указать объект который выполняет роль цели, игрока которым управляет и слой который будет «ловить» клики, и по которому будет ходить персонаж. Для этой цели я завел отдельный слой Terrain и присвоил его объекту выполняющему роль земли.
Вот и все, пробуйте и экспериментируйте.
Как работает Unity Character Controller (Контроллер Персонажа)?
Команда Unity3D заботится о рядовых пользователях и разработчиках игр. Поэтому в Unity была введена интересная система, называется она – Character Controller, а по русски – Контроллер Персонажа. Что же она делает и для чего вообще нужна? В основном она используется для управления персонажем от первого или третьего лица без использования физики Rigidbody.
Итак для начала нам следует подготовить сцену. Создадим Terrain, Меню GameObject>3d Object>Terrain
И создадим заготовку нашего персонажа. Для этого опять, Меню GameObject>Create Empty и назовем его Player. Затем делаем нашу камеру дочерней нашему свежесозданному Player.
Теперь добавим плееру компонент Character Controller. Для этого в окне инспектора нажмем кнопку Add Component и в появившемся списке в пункте Physics нажмем на Character Controller.
Когда контроллер персонажа добавлен к нашей заготовке, рассмотрим подробнее поля его настроек.
Slope Limit: этот параметр ограничивает возможность персонажу взбираться на различные препятствия. Например, по умолчанию стоит число 45, это значит, что если угол препятствия больше 45 градусов, то персонаж на него не сможет взобраться.
Step Offset: персонаж будет подниматься по лестнице, только если он ближе к земле, чем указанное значение.
Skin width: 2 коллайдера могут пересечься друг с другом на глубину, равную значению Skin Width.
Min Move Distance: если персонаж пытается переместиться ниже указанного значения, он не будет двигаться вообще.
Center: сдвиг коллайдера контроллера.
Radius: радиус коллайдера контроллера. Определяет, насколько жирный получился персонаж.
Height: высота коллайдера. Ну и, соответственно, высота контроллера. Например, если сделать это значение выше высоты дверных проемов, то персонаж просто застрянет в них.
Пока все значения оставим по умолчанию. В дальнейшем можно поменять их для лучшей работы контроллера. И как, это не странно, подготовка персонажа готова. Нам осталось написать небольшой скрипт управления камерой и нашим контроллером и персонаж будет готов.
Создадим новый скрипт под названием Player. Этот скрипт нам нужен для отдачи команд CharacterController, который и будет их выполнять, двигая и поворачивая персонажа. Для этого выберем в иерархии нашего персонажа и в инспекторе нажмем Add Component. Далее, в конце появившегося списка, нажимаем New Script, в появившемся поле ввода вводим название скрипта, в нашем случае – Player.
Завершающие действие – это кнопка Create and Add. Нажимаем! Отлично, скрипт создан и добавлен к нашему персонажу!
Откроем его, кликнув по его имени два раза.
В этом скрипте нам надо обьявить три переменные. Первая – это ссылка на CharaсterController. Вторая – скорость движения. Третья-скорость поворота. И укажем им значения по умолчанию 1 и 3 соответственно.
В методе Start, который, как мы знаем, вызывается при старте сцены, добавим строку, которая найдет и добавит компонент CharacterController к нашей переменной. Конечно же, при условии, что он присутствует на том же GameObject что и наш скрипт.
Теперь переходим к методу Update. Этот метод вызывается каждый кадр. В него для начала добавим строку, которая поворачивает наш персонаж вокруг оси Y, посредством клавиш leftArrow и RightArrow.
Затем мы задаем, куда нам двигаться. Точнее – вектор направления. Он у нас forward или z.
Затем мы устанавливаем скорость движения. В зависимости от того, какая клавиша нажата, она положительная или отрицательная. То есть вперед и назад.
И наконец, собираем все это вместе и передаем на Character Controller.
Сохраняем наш скрипт и переходим в Unity. На нашем персонаже должно быть два скрипта Charaster Controller и Player.
Жмем Play и стрелочками на клавиатуре двигаем и поворачиваем нашего персонажа. Урааа, побежали!
gunderson / FlyCamera.cs
This comment has been minimized.
Copy link Quote reply
NaoWeik commented May 7, 2018
This comment has been minimized.
Copy link Quote reply
cloutiertyler commented May 12, 2018
Awesome, thanks so much for posting it.
This comment has been minimized.
Copy link Quote reply
Wingspear commented May 26, 2018
This comment has been minimized.
Copy link Quote reply
RyanBreaker commented Jun 23, 2018 •
Check my fork for a cleaned-up copy. Also reduced default values because they were crazy fast in my project and made them public for easy modification in Unity’s Inspector, as well as changing Space to instead move the camera up and adding Left Control for moving it down.
This comment has been minimized.
Copy link Quote reply
zetaFairlight commented Oct 30, 2018
Thank you! BTW Me too I had to adjust the sensitivity.
This comment has been minimized.
Copy link Quote reply
arthurmarquis commented Apr 3, 2019
The associated script can not be loaded. Please fix any complie errors and assign a valid script.
This comment has been minimized.
Copy link Quote reply
PittMichelmann commented Jun 12, 2019
Perfect! Thank you for the saved time =)
This comment has been minimized.
Copy link Quote reply
sirmagid commented Jul 19, 2019
This comment has been minimized.
Copy link Quote reply
Amshu commented Sep 14, 2019
You saved a lot of peoples time, thanks
This comment has been minimized.
Copy link Quote reply
apoteet commented Dec 5, 2019
The associated script can not be loaded. Please fix any compiler errors and assign a valid script.
This happens if the class name doesn’t match the file name
This comment has been minimized.
Copy link Quote reply
ToniHiTriplix commented Dec 21, 2019
What needs to be done so that the camera does not fly?
This comment has been minimized.
Copy link Quote reply
RandGor commented Jan 1, 2020
What needs to be done so that the camera does not fly?
I guess you should add this script to MainCamera
This comment has been minimized.
Copy link Quote reply
altysheff commented Jan 21, 2020
the mouse cursor rests on the edge of the monitor
Правильная реализация передвижения персонажа
Почему один обьект проходит сквозь другой хотя у меня есть коллайдеры на обоих обьектах?
Почему мой персонаж во время движения проходит сквозь другой обьект, а потом его откидывает назад?
Как реализовать передвижение персонажа в Unity3d правильно?
Почему так часто используется передвижение через transform.position и почему это неправильно?
Почему мой персонаж движется с разной скоростью если проседает FPS?
Почему двигать персонажа через смену transform.position неправильно?
Как сделать прыжок от пола, но так что бы персонаж не мог бесконечно взлетать
Все эти вопросы, фактически, являются одним единым вопросом, который слишком уж часто встречается у начинающих.
Заодно создал тэг unity3d-faq
1 ответ 1
Перед прочтением важно знать
Хоть я здесь и разбираю в т.ч. нефизическое движение, я настоятельно рекомендую использовать ФИЗИЧЕСКОЕ движение. И переходить на нефизическое только в исключительных ситуациях.
Я буду использовать здесь 2 термина: «телепортация» и «плавное движение». В моем понимании:
Есть люди у которых мнение отличается.
Учтите, что все что написано ниже упирается в верхние значения терминов, а не эти.
Двигать обьекты в игровых движках можно следующими способами:
используя физический движок (движение обусловленное физической моделью игрового движка)
Движение реализуемое через CharacterController (здесь пока что не рассматривается т.к. новички в его сторону вообще не смотрят, может, позже распишу)
Новички очень часто использую телепортацию на каждом кадре, что есть критически неправильным подходом. Потом на SO появляются кучи клонов вопросов вроде «почему персонажа дергает возле стены?» или «почему он проходит сквозь стену?» или «почему пуля не всегда наносит урон?» и подобные.
Нужно запомнить всего одно правило: Двигать/поворачивать через присвоение transform.position / transform.rotation нельзя. Это порождает проблемы. В любом случае это вам вылезет боком.
Пример правильной реализации движения:
( на примере обьекта-шара )
в отличии от пестрящих дичью форумов, в т.ч. сервисе вопросов/ответов от юнити. Там в таких темах слишком часто пишут ответы те люди, которые понятия не имеют о правильном подходе.
Связанные с темой понятия:
Если обьект не обладает физическими свойствами (не имеет RigitBody) эти параметры и методы можно использовать для НЕфизического передвижения.
Например поворот камеры.
Или крутящийся куб на небосводе.
Мы не получим дергающуюся картинку при проседании кадров если сделаем НЕФИЗИЧЕСКОЕ движение правильно:
мы присваиваем в новую позицию:
Про физические свойства движения.
мы разово задаем вектор скачка. Только 1 долю секунды. Но он будет изменятся во времени автоматически равномерно уменьшаясь под силой тяжения. Пока не станет нулевым (верхняя точка прыжка), а потом не пойдет в минус по Y (падение), а потом не упадет на землю и не отскочит от нее (снова плюс по Y ) и так до полной остановки физической скорости обьекта на земле.
Если девайс с игрой сильно загружен, вызов методов Update() / FixedUpdate() тоже может просесть в скорости. И если в физике это учтено и без нас, то сейчас мы делаем НЕ физическое движение и именно по-этому это нужно учитывать добавлением даного множителя.
Но и без использования даного множителя у нас не появится проблем с провалами сквозь стены. Это просто фикс скорости.
Пример простой но хорошей НЕФИЗИЧЕСКОЙ реализации кода движения на примере персонажа.
Если в прошлом примере мы двигали шар, то было допустимо его толкать используя физ.модель. То есть мы использовали AddForce() для этих целей.
Давайте актуализируем этот код под даного персонажа. Мы заменим физический толчек обьекта на не-физическое, но ПЛАВНОЕ перемещение обьекта в пространстве:
С этим кодом мы получим такой результат:
С такой реализацией у нас не будет проблем вроде скачков скорости на проседании или повышении количества FPS, проваливаний, дерганости, прохождения сквозь стены или других неожиданностей.
Так же можно добавить анимацию бега на нашего персонажа (ну если бы это был не куб).
Но как же реализация на физике?
Да, можно подобное реализовать и на физике.
Наша прошлая версия скрипта имела несколько недостатков. А именно:
Давайте поместим на наш куб CapsuleCollider (минимальное торможение из-за силы трения) и заблочим в rigitBody rotateX и rotateZ (что б наш персонаж не падал на бок).
А потом нацепим на него вот этот скрипт:
Вы видите эту плавность, как будто человек бежит, останавливается, бежит в другую сторону? Красота!
А теперь вернитесь к прошлой гифке и присмотритесь. Движение совсем не такое 🙂 Там как буд-то рукой двигают шахматную фигуру по доске.
Ну и описанные выше баги поведения были пофикшены с такой реализацией.
Можно добавить еще физический материал нашему персонажу и откоректировать его поведение.
Вообще улучшать реализацию можно до бесконечности. Но, думаю, основные проблемы СПОСОБОВ ПЕРЕДВИЖЕНИЯ с которыми вы столкнетесь, я затронул 🙂
Оптимально использовать именно передвижение на базе физики.
Пытайтесь использовать исключительно физическое передвижение.
Реализация нестандартной физики движений.
Одним из моих любимейших примеров нестандартной физики движения является игра Ori and the Blind Forest
Такое перемещение/такие прыжки невозможно сделать на основе стандартной физики. Вероятнее всего, это делалось через нефизическое перемещение + костыли для получения нужных эфектов.
Сначала разрабатываются концепты движения. Они делаются в любом видеоредакторе с примитивными фигурами. Вот пример (если станет недоступным искать можно по Ori and the blind forest Enemy Concepts ) :
Обратите внимание на то, то здесь прорисовано не только перемещение обьекта, но и его вытягивания/сжатия. Изменения формы во время любого взаимодействия с внешним миром. В т.ч. выстрелы так же влияют на форму. А так же что указываются радиусы опознавания главного героя каждым отдельным врагом.
Костыли для каждого персонажа/врага свои собственные. Это делается что бы каждый из них обладал своей уникальной физикой. Сделать это на общей физике навряд ли возможно.
Движение реализовано «правильно» но предмет все равно пролетает сквозь стену
ДАЖЕ если вы реализовали физическое передвижение вашего персонажа, все равно может случится такое, что просчет CollisionDetect может проходить с ошибками. Такое бывает.
Для таких случаев есть настройки отвечающие за обработку CollisionDetect в настройках самого RigitBody.
Желательно такого не делать т.к. это негативно сказывается на производительности. Чем на большем количестве обьектов вы меняете эти настройки, тем более вероятно что вы делаете какую-то дичь, которую делать совсем не нужно. Считайте это спасательным кругом, а не панацеей. А если вы так будете делать, то рано или поздно вы прийдете на SO с вопросом почему игра тормозит, вас попросят показать код и ничего не найдут просто потому, что проблема тормозов не в коде. И намучаетесь вы с оптимизациями ой как сильно.