есть анимация ходьбы персонажа (Влево, Вправо, Вверх и Вниз) вызываемая при помощи индексов.
Существует задача : сохранять положение анимации персонажа (оставлять спрайт персонажа повёрнутым в сторону ходьбы "речь идёт о 2D сцене").
Для выполнения данной задачи написал скрипт (будет ниже), а так же создал анимационные клипы в 1 кадр (Где на каждом из них - персонаж повёрнут в нужную сторону).
Суть проблемы - анимация долго думает перед тем как смениться, персонаж уже начинает идти, а анимация, к примеру - смотреть налево, остаётся и только через пол секунды (может меньше) сменяется (Exit time на каждом переходе выставил на 0).
Думаю, проблема в скрипте или моём методе реализации данной процедуры. Прошу помощи и критики, заранее спасибо! (Мой скрипт)
Animator _anim;
bool a;
bool d;
bool w;
bool s;
void Start()
{
a = false;
d = false;
w = false;
s = false;
_anim = GetComponent<Animator>();
}
void FixedUpdate() {
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
if (h == -1)
{
_anim.SetInteger("State", 3);
a = true;
}
else if (h == 1)
{
_anim.SetInteger("State", 4);
d = true;
}
else if (v == 1)
{
_anim.SetInteger("State", 1);
w = true;
}
else if (v == -1 )
{
_anim.SetInteger("State", 2);
s = true;
}
else if (a == true && d == false && w == false && s == false)
{
_anim.SetInteger("State", 7);
a = false;
}
else if (d == true && a == false && w == false && s == false)
{
_anim.SetInteger("State", 6);
d = false;
}
else if (w == true && d == false && a == false && s == false)
{
_anim.SetInteger("State", 8);
w = false;
}
else if (s == true && d == false && w == false && a == false)
{
_anim.SetInteger("State", 5);
s = false;
}
}
}
У вас ошибка в этих if (h == -1)
строках. Значение Input.GetAxis хоть вертикальная, хоть горизонтальная не сразу становится -1 или 1, а постепенно, с шагом 0.05f. Note: The Horizontal and Vertical ranges change from 0 to +1 or -1 with increase/decrease in 0.05f steps. GetAxisRaw has changes from 0 to 1 or -1 immediately, so with no steps. Соответственно у вас и меняется анимация когда доберется до значения 1 или -1. Вам надо делать проверки такого рода: if (h > 0){...} if (h < 0) {...}
. По поводу FixedUpdate() или Update() там же сказано: This is frame-rate independent; you do not need to be concerned about varying frame-rates when using this value, поэтому делайте в зависимости от вашей логики.
В итоге - получился вот такой код, который исправно работает.
P.s. Спасибо добрым людям.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Anim : MonoBehaviour {
Animator _anim;
bool a; // Создаём переменные которые могут иметь значения (true или false).
bool d; // И будем их использовать для определения - была ли нажата клавиша или нет.
bool w;
bool s;
void Start() // При запуске программы, делаем переменные равными - false (Кнопка не была нажата)
{
a = false;
d = false;
w = false;
s = false;
_anim = GetComponent<Animator>();
}
void Update() // В данной функции действия происходят каждый кадр
{
float h = Input.GetAxis("Horizontal"); // Создаём переменную, которая будет принимать значение (-1 , 0 , 1) в зависимости от горизонтального перемещения
// Тем самым, сообщая, какая клавиша нажата - если -1 то "А", если 1 то "D", если 0 то не нажата
float v = Input.GetAxis("Vertical");// Создаём переменную, которая будет принимать значение (-1 , 0 , 1) в зависимости от вертикального перемещения
// Тем самым, сообщая, какая клавиша нажата - если -1 то "S", если 1 то "W", если 0 то не нажата
if (h < 0) // Если нажата кнопка налево (В моём случае это - "A"), выполнить следующее
{
_anim.SetInteger("State", 3); //Сменить индекс проигрываемой анимации, тем самым сменив её
a = true; // Задать значение переменной "a" - true
d = false;// Остальные переменный, как и в каждом последующем случае, мы делаем равными "false" ибо мы не всегда
// будем двигаться в одну сторону, возможно движение и наискосок, посредством одновременного нажатия двух клавиш
// а для данного метода включения анимации, необходимо иметь не более одной переменной со значением "true"
w = false;
s = false;
}
else if (h > 0)// Если нажата кнопка направо (В моём случае это - "D"), выполнить следующее
{
_anim.SetInteger("State", 4); // Здесь действия одни и те же, лишь меняется индекс анимации и переменная, которая станет - true
d = true;
a = false;
w = false;
s = false;
}
else if (v > 0)// Если нажата кнопка вверх (В моём случае это - "W"), выполнить следующее
{
_anim.SetInteger("State", 1);
w = true;
d = false;
a = false;
s = false;
}
else if (v < 0)// Если нажата кнопка вниз (В моём случае это - "S"), выполнить следующее
{
_anim.SetInteger("State", 2);
s = true;
d = false;
w = false;
a = false;
}
else if (a == true && d == false && w == false && s == false)// На данном этапе, осуществляется проверка - какая клавиша была нажата
// тем самым, определяя в какую сторону мы двигались и запуская соответствующую анимацию
{
_anim.SetInteger("State", 7);
a = false; // После того, как наша анимация, в данном случае (смотреть налево), включена. Нужно вернуть переменную "a" в значение - false
}
else if (d == true && a == false && w == false && s == false)
{
_anim.SetInteger("State", 6);
d = false;
}
else if (w == true && d == false && a == false && s == false)
{
_anim.SetInteger("State", 8);
w = false;
}
else if (s == true && d == false && w == false && a == false)
{
_anim.SetInteger("State", 5);
s = false;
}
}
}
Довольно странный у вас автомат в плане переходов. Если объект движется, например вправо, то встать в неподвижную позу вправо - RightStay
он может только после движения вправо, но никак не из любого состояния.
В итоге машина состояний становится чуть более логичной, что ли:
Что по логике вашего кода, что просто по человеческой логике начать смотреть вправо только после того, как персонаж двигался вправо. Такое работает со всеми направлениями.
Я использовал точно такие же номера состояний для переходов, как и у вас в коде - конфликтов быть не должно.
Также в аниматор был добавлен триггер, переключение которого будет условием перехода из состояния движения в состояния "простоя":
Для всех переходов от движения в любую сторону в "простой" в соответствующую сторону нужно добавить вот такой переход от нового триггера:
Ну и наконец финальный код, который, прошу заметить, очень сильно убавил в количестве строк и ненужных проверок с кучей ненужных булевых значений :)
public class Anim : MonoBehaviour {
Animator _anim;
void Start () {
_anim = GetComponent<Animator>();
}
void Update () {
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
if (h < 0) {
_anim.SetInteger("State", 3);
}
else if (h > 0) {
_anim.SetInteger("State", 4);
}
else if (v > 0) {
_anim.SetInteger("State", 1);
}
else if (v < 0) {
_anim.SetInteger("State", 2);
}
else {
// выставляет несуществующее состояние, чтобы не сработал переход
// AnyState -> MoveState
// по-хорошему это НЕ нужно выставлять каждый кадр
// лучше запомнить h и v предыдущего кадра, если предыдущий кадр
// и текущий равны - выставление State`а можно опустить
_anim.SetInteger("State", -1);
// вот такая простая манипуляция c конечным автоматом
// позволяет легко перейти в соответствующее idle состояние
// если мы находимся в движении - будет выбрана верная сторона
// если мы не двигаемся - триггер поменяет состояние, но ничего не поменяется
_anim.SetTrigger("Stopped");
}
}
}
Виртуальный выделенный сервер (VDS) становится отличным выбором
У меня проблема, разрабатываю сайт и нужно сделать отправку сообщений на почту админуТолько проблема в том, пользователь должен иметь сам...
На сайте есть разделы которые должны быть доступны только после оплаты пользователем доступа к нимВ качестве платёжной системы использую...
Не могу найти как отключить вывод исключенийПодскажите как это сделать? Имею ввиду, что не хотелось бы что бы это увидел кто то кроме меня
Назрел один вопрос: хорошая ли это практика, останавливать выполнение каких либо действий методом exit() (будь это контроллер, планировщик задач,...