Анимация открытия дверей лифта. Срабатывает позиция этажей одновременно
Нужна помощь. Создал лифт, создал анимацию, но из-за Update(), который постоянно обновляется на этаже, не срабатывает анимация (я так думаю, может и не прав). Вернее постоянно работает. Как правильно организовать в данных условиях корректное закрытие дверей при нажатии кнопки лифта и открытие дверей, когда лифт оказался на этаже? Я понимаю как анимация должна работать, но не могу понять как это сделать в данных условиях. По возможности, объясните подробно, так как 2 недели в unity. Спасибо за ответ.
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
[RequireComponent(typeof(AudioSource))]
public class Elevator_trigger : MonoBehaviour
{
[Header("Анимации")]
public Animator anim;
[Header("Лифт")]
public Transform floor_pos_1;
public Transform floor_pos_2;
public Transform floor_pos_3;
public GameObject Text_for_use_button;
public GameObject Elevator;
private int count_floors;
private float velocity = 5f;
private bool on_floor;
private bool on_move;
public int button_used_floor;
void Start()
{
anim.Play("DoorOpen");
}
public void GetCallFloor(int Calling_floor)
{
button_used_floor = Calling_floor;
}
void FixedUpdate()
{
if (on_floor == true)
{
Debug.Log("on_floor = true");
switch (button_used_floor)
{
case 1:
on_move = true;
on_floor = false;
Debug.Log("On 1st floor");
break;
case 2:
on_move = true;
on_floor = false;
Debug.Log("On 2nd floor");
break;
case 3:
on_move = true;
on_floor = false;
Debug.Log("On 3rd floor");
break;
}
}
if (on_move == true && button_used_floor == 1) //moving first floor
{
Elevator.transform.position = Vector3.MoveTowards(Elevator.transform.position, floor_pos_1.position, velocity * Time.deltaTime);
if (Elevator.transform.position.y == floor_pos_1.position.y)
{
on_move = false;
on_floor = true;
}
}
else if (on_move == true && button_used_floor == 2) //moving second floor
{
Elevator.transform.position = Vector3.MoveTowards(Elevator.transform.position, floor_pos_2.position, velocity * Time.deltaTime);
if (Elevator.transform.position.y == floor_pos_2.position.y)
{
on_move = false;
on_floor = true;
}
}
else if (on_move == true && button_used_floor == 3) // moving third floor
{
Elevator.transform.position = Vector3.MoveTowards(Elevator.transform.position, floor_pos_3.position, velocity * Time.deltaTime);
if (Elevator.transform.position.y == floor_pos_3.position.y)
{
on_move = false;
on_floor = true;
}
}
}
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
{
Debug.Log("in trigger");
on_floor = true;
}
}
private void OnTriggerExit(Collider other)
{
if (other.tag == "Player")
{
on_floor = false;
}
}
}
Ответы (1 шт):
Итак. Для решения данной проблемы я создал свой лифт с кнопками и возможностью захода/выхода из него. Заходить и выходить я тоже буду через кнопки но вы можете это заменить триггерами.
Если у вас 2д игра то все то же самое только без третьей координаты.
Используйте Update() а не FixedUpdate() для нефизического передвижения (без действий на rigidbody
MonoBehaviour.FixedUpdate has the frequency of the physics system. Источник из документации: https://docs.unity3d.com/ru/current/ScriptReference/MonoBehaviour.FixedUpdate.html )
Для начала создал лифт с дверью

Создал 2 анимации открытия и закрытия двери в сторону
Снимаем галку с обеих анимашек
В аниматоре создаем пустой прямоугольник и ставим его дефолтным правой кнопкой мыши, 2 наших анимации просто висят в воздухе
Поместил лифт на сцену, создал и разместил 3 точки CreateEmpty для координат наших этажей

Создал Canvas с кнопками для управления лифтом (В вашей игре его можно будет скрыть а потом включит если вы подошли к лифту и тд...)

Ну а теперь пишем простенький скрипт для лифта. Суть такова. создаем массив arrayOfFloors[] с нашими точками этажей (0 элемент - 1 этаж, 1 ел - 2 этаж ..)
Добавляем аниматор, скорость лифта. Создаем переменную Transform _targetFloor её мы будем менять при нажатии кнопок, а тем временем в Update() лифт будем всегда стремиться к _targetFloor. В Awake() _targetFloor ставим на 1-й этаж можно заменить если по умолчанию этаж другой.. Для управления анимациями создана корутина IEnumerator OpenAndCloseDoor() в которой мы проигрываем анимацию открытия двери, ждем 2 секунды и закрываем дверь. Вызывать мы её будем из метода OnEnterOrExitFromElevator() который в свою очередь будет у меня вызываться по кнопке входа выхода а у Вас может и по триггеру и тд.. Также при входе выходе я меняю переменную _isAnyoneInElevator потому что мы не модем ехать и нажимать на кнопки если мы не сели в лифт.
Метод OnGoToFloor(int floor) мы тоже будем вызывать по кнопке. Также в самом редакторе присвоим каждой кнопке свое значение floor для того чтобы этот метод знал на какой этаж мы хотим приехать. В самом методе просто присваиваем нашему _targetFloor соответствующий элемент массива arrayOfFloors[]. Ну а тут уже будет работать метод Update, который будет плавно нас переносить куда мы захотим:
using System.Collections;
using UnityEngine;
public class Elevator : MonoBehaviour
{
public Transform[] arrayOfFloors; // Массив координат этажей
public Animator doorAnimator;
public float elevatorSpeed = 5;
private bool _isAnyoneInElevator; // есть ли кто в лифте ???
private Transform _targetFloor; // позиция этажа на которую мы будем ехать
private float _elevatorPosition;
public void OnEnterOrExitFromElevator() // Ивент на кнопку захода / выхода из лифта. Можно будет заменить на `OnTriggerEnter` и тд
{
_isAnyoneInElevator = !_isAnyoneInElevator; // лифт пуст / не пуст
StartCoroutine(OpenAndCloseDoor()); // запуск корутины для проигрывания анимации закрытия / открытия дверей лифта
}
public void OnGoToFloor(int floor) // Ивент на кнопку нажатия кнопки лифта (1, 2, ...)
{
if (_isAnyoneInElevator) // если мы в лифте
{
_targetFloor = arrayOfFloors[floor - 1]; // меняем позицию этажа на нужную
}
}
private void Awake()
{
_targetFloor = arrayOfFloors[0]; // стандартная позиция лифта на 1м этаже
}
private void Update()
{
// наш лифт всегда будет стремиться к `_targetFloor`
_elevatorPosition = Mathf.Lerp(_elevatorPosition, _targetFloor.position.y, Time.deltaTime * elevatorSpeed); // плавное изменение _elevatorPosition по y-координате
transform.position = new Vector3(transform.position.x, _elevatorPosition, transform.position.z); // применение новой позиции, вычеслиной выше
}
private IEnumerator OpenAndCloseDoor() // корутина для проигрывания анимации закрытия / открытия дверей лифта
{
doorAnimator.Play("open_elevator");// открываем двери
yield return new WaitForSeconds(2); // ждем 2 секунды
doorAnimator.Play("close_elevator");// закрываем двери
}
}
Ну а теперь возвращаемся в редактор, цепляем скрипт на лифт и начинаем настройку скрипта в редакторе.

Все готово. Вот видео-результат: https://youtu.be/3-N2ns7fFnc Вот ссылка с проектом на гите: https://github.com/grouptout/elevator
Ps. Естественно мою реализацию можно подганять уже под разные задачи, условия, события и тд.
Забыл добавить. Чтобы дверь открывалась автоматически можно создать в классе булевую переменную например bool _wannaOpenDoor = false; тогда при вызове
public void OnGoToFloor(int floor) // Ивент на кнопку нажатия кнопки лифта (1, 2, ...)
{
if (_isAnyoneInElevator) // если мы в лифте
{
_wannaOpenDoor = true;
_targetFloor = arrayOfFloors[floor - 1]; // меняем позицию этажа на нужную
}
}
и в Update
private void Update()
{
// наш лифт всегда будет стремиться к `_targetFloor`
_elevatorPosition = Mathf.Lerp(_elevatorPosition, _targetFloor.position.y, Time.deltaTime * elevatorSpeed); // плавное изменение _elevatorPosition по y-координате
transform.position = new Vector3(transform.position.x, _elevatorPosition, transform.position.z); // применение новой позиции, вычеслиной выше
// если мы толькочто приехали
if(Math.Abs(transform.position.y - _targetFloor.position.y) < 0.02 && _wannaOpenDoor)
{
_wannaOpenDoor = false;
OnEnterOrExitFromElevator(); // автоматически открываем дверь после приезда
}
}
Теперь по приезду на этаж двери автоматически открываются. На гите обновил проект с этим функционалом. Вот видео-результат с автоматическими дверьми: https://youtu.be/g7LMmzTPECQ


