Скрипт на движение 3d персонажа в unity visual studio
«Префаб — это один из типов ресурсов, предназначений для многократного использования и хранящийся в Project View. Префаб может быть вставлен в любое количество сцен и многократно в одну сцену. Когда префаб добавляется в сцену, создаётся его экземпляр. Все экземпляры являются ссылками на оригинальный префаб и фактически его клонами. Независимо от того, как много экземпляров в проекте, при изменении префаба изменяются соответственно и все его экземпляры.»
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; //Высота прыжка
public static bool IsDrawWeapon; //Двоичная переменная, которая будет отвечать достануто ли у нас оружие.
public static float x = 0.0f; //угол поворота персонажа по оси x
void Start () <
IsDrawWeapon = false; //По умолчанию оружие у нас спрятано.
_speed = speed; //Задаем постоянное стандартное значение скорости персонажа
player = (GameObject)this.gameObject; //Задаем что наш персонаж это объект на котором расположен скрипт
>
void Update () <
if(IsDrawWeapon == true) //Если оружие вытащено
<
speed = _speed * 2; // Меняем скорость передвижени(я это сделал потому что, у этой моделки нету анимаций движения простым шагом с мечом. а понижать скорость анимации у бега получиться не красиво)
if(Input.GetKey(KeyCode.W)) //Если нажать W
<
player.transform.position += player.transform.forward * speed * Time.deltaTime; //Перемещаем персонажа в перед, с заданой скорость. Time.deltaTime ставится для плавного перемещения персонажа, если этого не будет он будет двигаться рывками
>
if(Input.GetKey(KeyCode.S))
<
speed = _speed / 2; //При передвижениии назад снижаем скорость перемещения
player.transform.position -= player.transform.forward * speed * Time.deltaTime; //Перемещаем назад
>
if(Input.GetKeyUp (KeyCode.S))
<
speed = _speed * 2; //Возвращаем cтандартное значение
>
if(Input.GetKey (KeyCode.A))
<
player.transform.position -= player.transform.right * speed * Time.deltaTime; //перемещаем в лево
>
if(Input.GetKey (KeyCode.D))
<
player.transform.position += player.transform.right * speed * Time.deltaTime; //перемещаем в право
>
if(Input.GetKey (KeyCode.Space))
<
player.transform.position += player.transform.up * jump * Time.deltaTime; //Прыгаем
>
if(Input.GetKey (KeyCode.Tab)) //При нажатии и на кнопку Tab
<
IsDrawWeapon = false; //Мы спрячем наше оружие.
>
>
else if(IsDrawWeapon == false) //Если оружие не спрятано. |||||| Сделано разделение на движения в зависимости от того вытащено ли у нас оружие или нет, потому что персонаж будет перемещаться сразной скорость у меня в этих случаях, как я уже написал из за отсутсвия некоторых анимаций у модельки.
<
speed = _speed;//Скорость в стандартное значение
if(Input.GetKey (KeyCode.LeftShift)) //Если зажать левый Shift
<
speed = _speed * 2; //Увеличиваем скорость перемещения(бег)
>
if(Input.GetKeyUp (KeyCode.LeftShift)) //Если отпустить
<
speed = _speed; //Возвращаем стандартное значение
>
if(Input.GetKey(KeyCode.W)) //Если нажать W
<
player.transform.position += player.transform.forward * speed * Time.deltaTime; //Перемещаем персонажа в перед.
>
if(Input.GetKey(KeyCode.S))
<
speed = _speed / 2;
player.transform.position -= player.transform.forward * speed * Time.deltaTime; //Перемещаем назад
>
if(Input.GetKeyUp (KeyCode.S))
<
speed = _speed; //Возвращаем cтандартное значение
>
if(Input.GetKey (KeyCode.A))
<
player.transform.position -= player.transform.right * speed * Time.deltaTime; //перемещаем в лево
>
if(Input.GetKey (KeyCode.D))
<
player.transform.position += player.transform.right * speed * Time.deltaTime; //перемещаем в право
>
if(Input.GetKey (KeyCode.Space))
<
player.transform.position += player.transform.up * jump * Time.deltaTime; //Прыгаем
>
if(Input.GetKey (KeyCode.Tab)) //при нажатии на кнопку таб
<
IsDrawWeapon = true; //Мы вытащим наше оружие
>
>
//Поворачиваем персонажа. Так как наша переменная x глобальна, из скрипта камеры в неё будем записывать длину на сколько сместился указатель мыши и по оси X и относительно этого будет повернут наш персонаж
Quaternion rotate = Quaternion.Euler (0,x,0); //Создаем новую переменную типа Quaternion для задавания угла поворота
player.transform.rotation = rotate; //Поворачиваем персонаж
codeusing UnityEngine;
using System.Collections;
public class CamMove : MonoBehaviour <
public Transform target; //Объект за которым летаем(Наш персонаж)
public float distance = 3.0f; //На каком ратоянии от него
public float xSpeed = 125.0f; //Чуствительность по Х
public float ySpeed = 50.0f; //Y Чуствительность
public float targetHeight = 2.0f; //Высота относительно объекта
//Минимальный и максимальный угол поворота Y инче камеру разверет, Дальше у нас будет простая функция для инвертации их в обратные числа
public float yMinLimit = -40;
public float yMaxLimit = 80;
//Максимальное удаление и приближение камеры к персонажу, искорость.
public float maxDistance = 10.0f;
public float minDistance = 0.5f;
public float zoomRote = 90.0f;
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; //Если камера столкнется с физ.объектомона остановиться
>
public void LateUpdate() <
if (target)/Если цель установлена(Персонаж)
//Меняем углы согласно положению мыши
x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
//Меняем дистанция до персонажа.
distance -= (Input.GetAxis ("Mouse ScrollWheel") * Time.deltaTime) * zoomRote * Mathf.Abs(distance);
distance = Mathf.Clamp (distance, minDistance, maxDistance);
y = ClampAngle(y,yMinLimit, yMaxLimit); //Вызыв самописной функции для ограничения углов поврот
movePlayer.x = x;
//Повернуть камеру согласно поченым данным
Quaternion rotation = Quaternion.Euler(y, x, 0);
transform.rotation = rotation;
//Двигаем камеру и следим за персонажем
Vector3 position = rotation * new Vector3(0.0f, targetHeight+0.5f, -distance) + target.position;
transform.position = position;
//Следуйщи код нужен что бы камера не проваливалась по ланшафт
RaycastHit hit;
Vector3 trueTargetPosition = target.transform.position - new Vector3(0, -targetHeight,0);
if(Physics.Linecast (trueTargetPosition, transform.position, out hit))
<
float tempDistance = Vector3.Distance (trueTargetPosition, hit.point) - 0.28f;
position = target.position - (rotation * Vector3.forward * tempDistance + new Vector3(0, -targetHeight, 0));
transform.position = position;
>
>
>
//Меняем значения углов
public static float ClampAngle (float angle, float min, float max) <
if(angle < -360)
angle += 360;
if(angle > 360)
angle -= 360;
return Mathf.Clamp (angle, min, max);
>
>
Скрипт кидаем на камеру. Камера должна быть перемещена в префаб персонажа в окне «Hierarchy». А в компоненте скрипта на камере в поле «Target» долже быть помещен наш префаб из окна «Hierarchy».
Анимация
Создадим новый скрипт и назовем его «AnimatePlayer»
using UnityEngine;
using System.Collections;
public class AnimatePlayer : MonoBehaviour
public void Start ()
<
// Устанавливаем все клипы анимации в режим цикла
animation.wrapMode = WrapMode.Loop;
// Кроме следующих
animation["Attack01"].wrapMode = WrapMode.Once;
animation["jump"].wrapMode = WrapMode.Once;
animation["Skill"].wrapMode = WrapMode.Once;
//У них одиночное выполнение
//Останавливаем выполнение анимаций.
animation.Stop();
>
public void Update () <
// На основе нажатой клавиши выполняем анимацию
if(movePlayer.IsDrawWeapon == false) //Если оружие не вытащено
<
if (Input.GetAxis("Vertical") > 0.0f) //Проверяем на изминениея позиции персонажа повертикали, если да
<
if(movePlayer.speed == movePlayer._speed * 2) //Проверяем скорость Передвижения персонажа,
<
animation.CrossFade ("Run00"); //Если зажата клавиша shift, значит грузим анимацию бега
>
else
<
animation.CrossFade("Walk"); //В противном случаее ходьбу
>
>
else if(Input.GetAxis("Vertical") < 0.0f) //Далее все по анологии
<
if(movePlayer.speed == movePlayer._speed * 2)
<
animation.CrossFade ("B_Run00"); //бег назад
>
else
<
animation.CrossFade ("B_Walk"); //ходьба назад
>
>
else if (Input.GetAxis("Horizontal") > 0.0f)
<
if(movePlayer.speed == movePlayer._speed * 2)
<
animation.CrossFade ("R_Run00"); //бег в право
>
else
<
animation.CrossFade ("R_Walk"); //Шагание в право
>
>
else if(Input.GetAxis("Horizontal") < 0.0f)
<
if(movePlayer.speed == movePlayer._speed * 2)
<
animation.CrossFade ("L_Run00"); //лево
>
else
<
animation.CrossFade ("L_Walk"); //лево
>
>
else if(Input.GetKey (KeyCode.Space)) //если сделан прыжок
animation.Play ("Jump_NoBlade"); //Включаем анимацию прыжка
>
else
<
animation.CrossFade("Idle"); //просто стоим
>
>
else if(movePlayer.IsDrawWeapon == true) //если оружие вытащено
<
if (Input.GetAxis("Vertical") > 0.0f)
<
animation.CrossFade ("Run"); //бег в перед
>
else if(Input.GetAxis("Vertical") < 0.0f)
<
animation.CrossFade ("B_Run"); //назад
>
else if (Input.GetAxis("Horizontal") > 0.0f)
<
animation.CrossFade ("R_Run"); //в право
>
else if(Input.GetAxis("Horizontal") < 0.0f)
<
animation.CrossFade ("L_Run"); //в лево
>
else if(Input.GetKey (KeyCode.Space))
<
animation.Play ("jump"); //Прыжок
>
else
<
animation.CrossFade("AttackStandy"); //просто стоим
>
//Анимация атаки
if (Input.GetMouseButton (0)) //Если нажать маус 1
animation.CrossFade("Attack01"); //Включаем анимацию атаки
if (Input.GetMouseButton (1)) //Если нажать маус 2
animation.CrossFade("Skill"); //Включаем анимацию скила
>
>
>
Почему один обьект проходит сквозь другой хотя у меня есть коллайдеры на обоих обьектах?
Почему мой персонаж во время движения проходит сквозь другой обьект, а потом его откидывает назад?
Как реализовать передвижение персонажа в Unity3d правильно?
Почему так часто используется передвижение через transform.position и почему это неправильно?
Почему мой персонаж движется с разной скоростью если проседает FPS?
Почему используя присвоение в transform.position используют множитель Time.deltaTime ?
Почему двигать персонажа через смену transform.position неправильно?
Почему при использовании Velocity или .AddForce() не используется множитель Time.deltaTime ?
Как сделать прыжок от пола, но так что бы персонаж не мог бесконечно взлетать
Почему когда платформа движется, персонаж стоящий на платформе остается на месте?
Почему пуля не всегда наносит урон?
Все эти вопросы, фактически, являются одним единым вопросом, который слишком уж часто встречается у начинающих.
Заодно создал тэг unity3d-faq
1 ответ 1
В любом случае на персонаж должен быть навешан RigidBody - скрипт отвечающий за физику персонажа (силу притяжения, силу трения и т.д.)
Хоть я здесь и разбираю в т.ч. нефизическое движение, я настоятельно рекомендую использовать ФИЗИЧЕСКОЕ движение. И переходить на нефизическое только в исключительных ситуациях.
В коде не должно быть прямой привязки к кнопкам. Должна быть привязка к параметрам Input Manager . Которые можно найти в: Edit -> Project Settings -> Input . Нужно принять это как аксиому и не отходить, несмотря, на то что вы там нагуглите.
Я буду использовать здесь 2 термина: "телепортация" и "плавное движение". В моем понимании:
Плавное движение - перерасчет позиции обьекта в рамках физики или паралельно физике на вызове FixedUpdate() .
Телепортация - перерасчет позиции обьекта на промежутке времени большем чем fixedDeltaTime .
Есть люди у которых мнение отличается.
- Плавное движение - исключительно физическое движение
- Телепортация - изменение позиции вручную или использование .Translate() метода.
Учтите, что все что написано ниже упирается в верхние значения терминов, а не эти.
Двигать обьекты в игровых движках можно следующими способами:
используя физический движок (движение обусловленное физической моделью игрового движка)
движение НЕфизическое. Неправильный подход -- подход телепортации на каждом кадре. (в Update() )
движение НЕфизическое. Правильный подход -- плавное передвижение обьекта между кадрами (паралельно каждому просчету физики) (все равно желательно не использовать)
Движение реализуемое через CharacterController (здесь пока что не рассматривается т.к. новички в его сторону вообще не смотрят, может, позже распишу)
На практике метод передвижения подбирается под конкретного персонажа[персонажа -- не буквально. Это может быть и автомобиль]. В одном случае лучше будет физическое перемещение. В другом -- нефизическое. В третьем случае будет лучше всего CharacterController. Понимание что лучше в каком случае прийдет с практикой.
Новички очень часто использую телепортацию на каждом кадре, что есть критически неправильным подходом. Потом на SO появляются кучи клонов вопросов вроде "почему персонажа дергает возле стены?" или "почему он проходит сквозь стену?" или "почему пуля не всегда наносит урон?" и подобные.
Нужно запомнить всего одно правило: Двигать/поворачивать через присвоение transform.position / transform.rotation нельзя. Это порождает проблемы. В любом случае это вам вылезет боком.
Все для чего нужно это -- телепортация в другое место обьекта, но никак не его движения.
( на примере обьекта-шара )
Обратите внимание что за основу взят код из официальной документации/туториалов по юнити. Если есть несколько источников информации по какому-то мелкому но часто задаваемому вопросу (например движение персонажа ) -- выбирайте официальную документацию! Там точно фигни не посоветуют,
Есть Update() -- этот метод вызывается на каждой прорисовке кадра. Time.DeltaTime - это расчетное время между прорисовкой двух кадров. Если FPS проседает на компьютере, то этот параметр возрастает пропорционально проседанию.
Есть FixedUpdate() - это метод который вызывается при перепросчете физики. Time.FixedDeltaTime , как вы уже догадались, это время между вызовами FixedUpdate() . Оно может изменятся вручную через настройки, но упирается в физические возможности машины на которой игра будет запущена.
Если обьект не обладает физическими свойствами (не имеет RigidBody) эти параметры и методы можно использовать для НЕфизического передвижения.
Например поворот камеры.
Или крутящийся куб на небосводе.
Или движущийся изображение поезда где-то далеко, к которому нельзя подойти близко. Физика такому обьекту просто ни к чему -- это просто лишняя трата ресурсов
но, даже, в этом случае предпочтительно использовать Transform.Translate , но про это позже
Мы не получим дергающуюся картинку при проседании кадров если сделаем НЕФИЗИЧЕСКОЕ движение правильно:
ВАЖНО: . ПРИМЕР ВРЕДНОГО КОДА. Не делайте так!
мы присваиваем в новую позицию:
- старую позицию
- направление движения
- скорость передвижения умноженную на Time.deltaTime .
Поэтому, даже, если, у нас было 60 кадров и случилось проседание до 10 кадров -- скорость вращения/движения обьекта не будет изменятся. Ведь, мы ее учитываем вместе с проседанием кадров.
Допустим мы двигаем обьект через rb.Velocity или через AddForce() , то это физическое движение обьекта. То есть она может изменятся во времени сама под действием неких физических законов. Например, мы задумали сделать прыжок персонажа:
мы разово задаем вектор скачка. Только 1 долю секунды. Но он будет изменятся во времени автоматически равномерно уменьшаясь под силой тяжения. Пока не станет нулевым (верхняя точка прыжка), а потом не пойдет в минус по Y (падение), а потом не упадет на землю и не отскочит от нее (снова плюс по Y ) и так до полной остановки физической скорости обьекта на земле.
Допустим, мы двигаем изменением transform.Positon нашего плеера вперед по нажатию клавиши "пробел". В какой-то момент мы перестаем нажимать кнопку -- движение резко остановится и замрет. Это потому, что наше движение НЕ является физическим. Допустим мы подойдем к стенке и попробуем пройти на нее. Т.к. мы занимаемся телепортацией обьекта, то наш персонаж сначала дойдет до стенки, а потом телепортируется ВНУТРЬ нее, после чего Collider ее вытолкнет из себя. Как глубоко телепортируется внутрь зависит лишь от того, на какое расстояние мы телепортируем нашего персонажа за кадр. То есть это "Bad Practice" так реализовать перемещение персонажа.
Но в то же время есть и допустимое не-физическое перемещение. Это использование метода Transform.Translate() . Это (вроде как) тоже телепортация, но с попыткой плавного нефизического перемещения обьекта. Но использование этого метода не освобождает нас от использования deltaTime/fixedDeltaTime, как в примере оф.документации.
( Снова таки - если на вашем обьекте есть RigidBody - наверняка нужно использовать физическое перемещение все равно! )
Если девайс с игрой сильно загружен, вызов методов Update() / FixedUpdate() тоже может просесть в скорости. И если в физике это учтено и без нас, то сейчас мы делаем НЕ физическое движение и именно по-этому это нужно учитывать добавлением даного множителя.
Но и без использования даного множителя у нас не появится проблем с провалами сквозь стены. Это просто фикс скорости.
Если в прошлом примере мы двигали шар, то было допустимо его толкать используя физ.модель. То есть мы использовали AddForce() для этих целей.
Допустим у нас персонаж -- человек, а не шар. Давай создадим вместо человека его подобие -- высокий куб 0.8х1.8х0.3 и попробуем нацепить на него наш скрипт движения шара. Выйдет следующее:
То есть когда мы пытаемся подвигать, наш персонаж падает (мы ж его толкаем, логично!). Когда он упал -- он не может двигатся из-за силы трения. Зато мы можем двигать его в прыжке. :)
Давайте актуализируем этот код под даного персонажа. Мы заменим физический толчек обьекта на не-физическое, но ПЛАВНОЕ перемещение обьекта в пространстве:
С этим кодом мы получим такой результат:
С такой реализацией у нас не будет проблем вроде скачков скорости на проседании или повышении количества FPS, проваливаний, дерганости, прохождения сквозь стены или других неожиданностей.
Теперь мы можем занятся украшательствами -- например повороты тела. Довольно приятно реализованы повороты вот здесь: Как сделать управление, как в игре "Overcooked"?
Так же можно добавить анимацию бега на нашего персонажа (ну если бы это был не куб).
Да, можно подобное реализовать и на физике.
Наша прошлая версия скрипта имела несколько недостатков. А именно:
- нужно было вручную отмечать каждый из предметов от которого мы можем прыгать. То есть добавив ящик на пол, нам нужно еще и его отметить тэгом Ground.
- если поставить кучу ящиков вертикально, присвоить каждому из них тэг "Ground", то просто подойдя к вертикальной стене из ящиков мы сможем взлететь вверх). То есть нам не важно к чему мы дотрагиваемся -- к полу или к стене -- оно давало нам возможность прыгать.
- наше движение все так же было НЕ физическим. То есть если мы начнем двигать игрока влево-вправо то он будет резко останавливатся а потом резко двигатся в противоположную сторону. В живом мире так не бывает.
Вспомните уроки физкультуры, когда нужно было пробежать 30 метров вперед, взять палочку, пробежать 30 метров назад, положить палочку и еще раз 30 метров в другую сторону. Что случалось с бегуном в этот момент если посмотреть сбоку? Сначала скорость растет, потом достигает пика, а потом торможение, взятие палочки, бег в другую сторону -- снова возрастание скорости. Никаких резких скачков. Этого можно добится именно передвижением при помощи физики.
Давайте поместим на наш куб CapsuleCollider (минимальное торможение из-за силы трения) и заблочим в rigidBody rotateX и rotateZ (что б наш персонаж не падал на бок).
А потом нацепим на него вот этот скрипт:
Вы видите эту плавность, как будто человек бежит, останавливается, бежит в другую сторону? Красота!
А теперь вернитесь к прошлой гифке и присмотритесь. Движение совсем не такое :) Там как буд-то рукой двигают шахматную фигуру по доске.
Ну и описанные выше баги поведения были пофикшены с такой реализацией.
Можно добавить еще физический материал нашему персонажу и откоректировать его поведение.
Вообще улучшать реализацию можно до бесконечности. Но, думаю, основные проблемы СПОСОБОВ ПЕРЕДВИЖЕНИЯ с которыми вы столкнетесь, я затронул :)
Оптимально использовать именно передвижение на базе физики.
Пытайтесь использовать исключительно физическое передвижение.
Одним из моих любимейших примеров нестандартной физики движения является игра Ori and the Blind Forest
Такое перемещение/такие прыжки невозможно сделать на основе стандартной физики. Вероятнее всего, это делалось через физическое перемещение + костыли для получения нужных эфектов которые противоречат стандартной физике.
Сначала разрабатываются концепты движения. Они делаются в любом видеоредакторе с примитивными фигурами. Вот пример (если станет недоступным искать можно по Ori and the blind forest Enemy Concepts ) :
Обратите внимание на то, то здесь прорисовано не только перемещение обьекта, но и его вытягивания/сжатия. Изменения формы во время любого взаимодействия с внешним миром. В т.ч. выстрелы так же влияют на форму. А так же что указываются радиусы опознавания главного героя каждым отдельным врагом.
Костыли для каждого персонажа/врага свои собственные. Это делается что бы каждый из них обладал своей уникальной физикой. Сделать это на общей физике навряд ли возможно.
ДАЖЕ если вы реализовали физическое передвижение вашего персонажа, все равно может случится такое, что просчет CollisionDetect может проходить с ошибками. Такое бывает.
Для таких случаев есть настройки отвечающие за обработку CollisionDetect в настройках самого RigidBody.
Желательно такого не делать т.к. это негативно сказывается на производительности. Чем на большем количестве обьектов вы меняете эти настройки, тем более вероятно что вы делаете какую-то дичь, которую делать совсем не нужно. Считайте это спасательным кругом, а не панацеей. А если вы так будете делать, то рано или поздно вы прийдете на SO с вопросом почему игра тормозит, вас попросят показать код и ничего не найдут просто потому, что проблема тормозов не в коде. И намучаетесь вы с оптимизациями ой как сильно.
Ожидаемый результат: вращение объекта только по оси Y и не делать смещения по Z.
Фактический результат:
UPD:
Вращение во круг своей оси работает, необходимо двигать только по Y.
Движение ограничено, то есть, когда position.Y дошло до определенного значения, оно должно изменить направление.
Предполагается, что кубик должен вращаться вверх-вниз.
В каком смысле через анимацию? - тебе же нужно сделать мотание объекта туда-сюда так? Плюс вращение. Залезай в анимацию объекта, добавь несколько кадров и сделай так, чтоб он с 1 по 10 кадр например ехал вправо, а с 10 по 20 - влево. Плюс вращение. в целом это называется tween .
2 ответа 2
У меня есть следующие предположения:
У тебя обьект, видимо, находится в другом обьекте. И как следствие -- используются локальные оси вместо глобальных. Или же ты в коде намадрил(влом разбиратся, все равно не похоже на толковое решение)
Сделай просто смену угла через задавание нового Rotation. Все.
На вскидку код будет что-то вроде:
не проверял и юнити запускал давно, но должно заработать, думаю.
Или же сделай что-то вроде:
Кроме того не имеет смысла делать Vector3.MoveTowards если это апдейт. - можешь сказать, что это значит? а где делать MoveTowards?
я не совсем правильно написал т.к. попутал с другим методом) Его нужно использовать когда тебе нужно что бы обьект взаимодействовал с другими обьектами(коллайдеры) -- что в твоем примере не нужно, а так же когда нужно двигать обьект от точки к точке(двигать! А не поворачивать. ). А для поворачивания(что бы было с взаимодействием коллайдерами, что тебе так же нафиг не нужно в даном примере) нужно использовать Vector3.RotateTowards
Логика должна быть какой-то такой
Также можно двигать объект не только вниз вверх, но и куда угодно в пределах размаха. Для этого нам поможет функция Vector3.Distance() . Чтобы рандомно задавать направление, можно немного изменить код и дописать функцию, которая будет это делать за нас. Код будет выглядеть примерно так:
А с помощью enum мы можем сделать скрипт более универсальным, выбирая как нам передвигать тот или иной объект. Ниже идёт улучшенная версия данного скрипта с доработками.
Здравствуйте! В этом уроке мы создадим нашего персонажа и научим его двигаться.
Для этого нам нужен спрайт персонажа. Для себя я выбрал вот такой пак со спрайтами:
Дальше переносим спрайт на сцену, который мы хотим:
Теперь нам надо добавить физику нашему персонажу, для этого в окне Инспектора нажимаем Add Component и выбираем RigidBody2D :
Также необходимо добавить само тело . Добавляем Box Collider 2D и нажимаем на значок:
Дальше у спрайта появится зеленая обводка , которая обозначает площадь тела . Подгоните размеры под спрайт.
Теперь же необходимо добавить тело земле , чтобы персонаж не проваливался сквозь неё: добавляем TileMap Collider 2D . Можно заметить, что у земли добавились зелёные линии, а если еще лучше присмотреться, то можно заметить, что эти линии находятся между тайлами, а это нам не нужно. Поэтому мы добавляем ещё Composite Collider 2D , а в TileMap Collider 2D ставим галочку у параметра Used By Composite . И о чудо, как теперь всё прекрасно выглядит!
Теперь можно запустить Игровой режим . Но что мы видим! Наша земля падает. Это случилось из-за автодобавления Rigid Body 2D , просто вместо Dynamic ставим Static . Вуа-ля, земля не падает!
Метод Start() исполняется, когда мы запускаем игру, а Update() выполняется каждый кадр .
Давайте проинициализируем переменные fox типа Rigidbody2D и speed типа float :
Теперь нам надо добавить движение нашей Лисе. Для этого в методе Update() (а лучше в FixedUpdate() , т.к. мы взаимодействуем с физическим объектом в скрипте; за уточнение спасибо Василию Курбатову , комментарий которого закреплен под этой статьёй; также уточню, что все взамидойсвтия с физ. объектами, которые будут в следующих уроках следует также добавлять именно в FixedUpdate() ) добавим одну сточку:
Не пугайтесь, сейчас расскажу, что она делает:
- fox.velocity - это скорость Лисы, и, как известно, у скорости есть направление, т.е. вектор ( new Vector2() );
- Input.GetAxisRaw() - это первый параметр вектора ( X ). Он принимает соответствующие нажатия для передвижения вправо/влево;
- *speed - это коэффициент скорости, который можем сами задать в интерфейсе Unity;
- fox.velocity.y - это координата Y Лисы.
Таким образом, эта строка создаёт вектор, который начинается на координатах Лисы и который направлен влево/вправо.
Теперь необходимо добавить прыжок . Для этого надо отслеживать нажатие клавиши (например Space ). Чтобы это делать, надо в методе Update() добавить проверку нажатия:
В условии мы проверяем на нажатие Space . Если произошло нажатие, то мы Лисе добавляем вектор, направленный вверх.
Но нам не хватает одной детали: проверки на "опору":
В условии мы добавили grounded , т.е. если мы нажали на Space и Лиса на земле , то только тогда будет прыжок. Сам же Grounded только тогда принимает значение true , когда в радиусе находится слой ground .
Чтобы добавить этот слой в Unity выбираем группу тайлов земли и нажимаем в Инспекторе Layer, Add layer (Добавить Слой):
Дальше создаём дочерний от нашего персонажа пустой игровой объект и переносим его в ноги. Затем возвращаемся к нашему персонажу.
В Ground Check я добавил пустой объект , а в Ground добавил тот слой, который только что создал.
В этом уроке мы научились управлять персонажем и поправили баги в его управлении.
В следующем уроке мы добавим анимацию нашему персонажу при движении.
Теперь сделаем само передвижение игрока вперёд при нажатии на "W" или стрелку вверх. Это делаем в методе void Update()! Для этого мы будем прибавлять позицию. Например вперёд.
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
<
player.transform.position += player.transform.forward * speed * Time.deltaTime;
>
Мы прибавили позицию вперёд (forward) и умножили на скорость, а точнее её переменную. И обязательно надо умножить на кадры в секунду (deltaTime).
Таким же образом сделаем движение назад. Только будем отнимать позицию.
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
<
player.transform.position -= player.transform.forward * speed * Time.deltaTime;
>
Таким же образом можем сделать и вправо и влево (right, left), но я сделаю просто поворот игрока, при нажатии на "A" или "D".
Я буду использовать "Rotate()". Чтобы поворачивать по оси "Y", я буду использовать "up" и "down". Кстати, для этого ещё надо объявить переменную "public int speedRotation = 3". И пишем в условиях.
if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
<
player.transform.Rotate(Vector3.down * speedRotation);
>
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
<
player.transform.Rotate(Vector3.up * speedRotation);
>
Ну. Сейчас пришло время анимировать. Я записываю анимацию в самой юнити. Это можно открыть в "Window" => "Animation". В этом окне мы можем анимировать куб. Итак. Пропустим момент создания анимации. Давайте теперь создадим переменную анимации.
Теперь мы будем его воспроизводить через "CrossFade". Воспроизводить буду в условиях ходьбы вперёд и назад. Чтобы воспроизвести, нужно написать.
Итак. У нас получился хороший код. Сейчас мы сделаем прыжок. Всё так же просто. Опять мы будем прибавлять позицию. Только вверх (up).
И так же с новой переменной анимации "public AnimationClip anima2;"? так же добавим и переменной "public int jumpSpeed = 50;". И мы получаем условие.
if (Input.GetKeyDown(KeyCode.Space))
<
player.transform.position += player.transform.up * jumpSpeed * Time.deltaTime;
>
using UnityEngine;
using System.Collections;
public class Move : MonoBehaviour public GameObject player;
public int speedRotation = 3;
public int speed = 5;
public AnimationClip anima;
public int jumpSpeed = 50;
void Start () <
player = (GameObject)this.gameObject;
animation.AddClip(anima, "animCube");
>
void Update() if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
<
player.transform.position += player.transform.forward * speed * Time.deltaTime;
animation.CrossFade("animCube");
>
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
<
player.transform.position -= player.transform.forward * speed * Time.deltaTime;
>
if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
<
player.transform.Rotate(Vector3.down * speedRotation);
>
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
<
player.transform.Rotate(Vector3.up * speedRotation);
>
if (Input.GetKeyDown(KeyCode.Space))
<
player.transform.position += player.transform.up * jumpSpeed * Time.deltaTime;
>
>
>
Надо только повесить его на куб и указать всё в инспекторе. Ах да. Можно поставить физику кубу, для более реалистичного прыжка.
Пример!
Всем спасибо)
Читайте также: