[Unity] Попытка реализовать контроллер от третьего лица (второе, мобильное управление ①)
[Заявление] Этот контроллер от третьего лица является репродукцией контроллера от третьего лица в активе Unity Star. При необходимости вы можете напрямую загрузить актив и изучить его. Мне лично не нравится, когда я заново изобретаю велосипед, но у официального контроллера есть некоторые неудовлетворительные ошибки, когда я его использую. Тем не менее, контроллер выглядит довольно хорошо для меня, и хотя бесшовная анимация невозможна, персональные проекты должны сначала выяснить, как заставить ее двигаться.
[Версия] Этот проект основан на версии Unity [2021.3lts].
Выберите, как двигаться
На данный момент есть два основных: 1.rig+collider.2.CharactorController
Здесь, чтобы изучить и учесть, что тип самоделки не требует слишком частого физического моделирования, я выбрал второй.
Использовать Контроллер Персонажей
[Примечание] Вот мой код, постепенно разумный мыслительный процесс, если вы хотите, чтобы код сразу перетащили в конец.
двигаться вверх
Сначала смонтируйте часть ввода, которую мы подготовили ранее для персонажа, который будет использоваться позже.
Затем создайте MoveController и прикрепите созданный скрипт к персонажу.
Чтобы смонтировать CharacterController для персонажа,
мы используем метод Move для CharacterController:
Vector3 targetDir = Vector3.forward;
_characterController.Move(targetDir);
Вернувшись в игровой тест, персонаж движется вперед.
направление управления
var _currentInput = new Vector3(_inputsMassage.move.x, 0, _inputsMassage.move.y);
Vector3 targetDir = currentInput;
_characterController.Move(targetDir * Time.deltaTime);
Я могу двигаться вперед-назад, влево-вправо, с тестом проблем нет, тогда мне нужно о чем-то подумать
думаю о поведении персонажа
В любой момент, пока мы нажимаем вперед, персонаж должен идти впереди нас. Нам нужно только извлечь размер движения.Сначала
определите скорость ходьбы, а затем оцените, есть ли ввод:
public float walkSpeed = 1.5f;
private float _currentSpeed;
//首先将移动速度赋予临时变量,考虑到有可能在其他地方使用,我们将其存储起来
_currentSpeed = walkSpeed;
//判断是否进行移动输入
if (_inputsMassage.move == Vector2.zero) _currentSpeed = 0;
Мы разделим персонажа на несколько состояний, и сначала займемся ходьбой.
_characterController.Move(targetDir * _currentSpeed * Time.deltaTime);
В фиксированном состоянии его скорость движения фиксирована, поэтому мы думаем, что входное движение предназначено только для направления, а размер определяется состоянием.
Мы нормализуем _currentInput выше, чтобы получить его единичный вектор (на самом деле он похож на единичный вектор, мы просто подтверждаем это)
var _currentInput = new Vector3(_inputsMassage.move.x, 0, _inputsMassage.move.y).normalized;
Итак, теперь рассмотрим случай нажатия влево и вправо:
при нажатии влево или вправо наш персонаж должен совершать поворот,
if (_inputsMassage.move!=Vector2.zero)
{
_targetRotation = Mathf.Atan2(currentInput.x, currentInput.z) * Mathf.Rad2Deg;
}
Тогда targetDir выше должен соответствовать этому углу:
Vector3 targetDir = Quaternion.Euler(0.0f, _targetRotation, 0.0f) * Vector3.forward;
Здесь угол Эйлера используется для поворота вперед на требуемый угол.
Мы протестировали и обнаружили, что между этими и предыдущими эффектами нет никакой разницы, зачем делать столько бессмысленных вещей?
Это подготовлено для того, чтобы камера позже контролировала направление, конечно же, в текущем коде такого контента нет;
ладно, до сих пор мы только определяли направление движения персонажа. Но наш персонаж не меняет своего направления. Давайте займемся этим дальше.
Мы используем Mathf.SmoothDampAngle для поворота
[Tooltip("角色光滑旋转时间")]
private float RotationSmoothTime = 0.12f;
[Tooltip("在角色光滑旋转过程中的速度")]
private float _rotationVelocity;
if (_inputsMassage.move!=Vector2.zero)
{
_targetRotation = Mathf.Atan2(currentInput.x, currentInput.z) * Mathf.Rad2Deg;
float rotation = Mathf.SmoothDampAngle(transform.eulerAngles.y, _targetRotation, ref _rotationVelocity,RotationSmoothTime);
transform.rotation = Quaternion.Euler(0.0f, rotation, 0.0f);
}
На этом заканчивается первая подвижная часть. Не волнуйтесь, в мобильной версии еще много нерешенных проблем, и мы будем решать их шаг за шагом.
код
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class ThirdPlayerMoveController : MonoBehaviour
{
CharacterController _characterController;
PlayerInputsMassage _inputsMassage;
[Header("设置")]
[Tooltip("这将决定普通行走时的速度")]
public float walkSpeed = 1.5f;
private float _currentSpeed;
private float _targetRotation = 0.0f;
[Tooltip("角色光滑旋转时间")]
private float RotationSmoothTime = 0.12f;
[Tooltip("在角色光滑旋转过程中的速度")]
private float _rotationVelocity;
// Start is called before the first frame update
void Start()
{
_characterController = GetComponent<CharacterController>();
_inputsMassage = GetComponent<PlayerInputsMassage>();
}
private void FixedUpdate()
{
Move();
}
private void Move()
{
//首先将移动速度赋予临时变量,考虑到有可能在其他地方使用,我们将其存储起来
_currentSpeed = walkSpeed;
//判断是否进行移动输入
if (_inputsMassage.move == Vector2.zero) _currentSpeed = 0;
var currentInput = new Vector3(_inputsMassage.move.x, 0, _inputsMassage.move.y).normalized;
if (_inputsMassage.move!=Vector2.zero)
{
_targetRotation = Mathf.Atan2(currentInput.x, currentInput.z) * Mathf.Rad2Deg;
float rotation = Mathf.SmoothDampAngle(transform.eulerAngles.y, _targetRotation, ref _rotationVelocity,
RotationSmoothTime);
transform.rotation = Quaternion.Euler(0.0f, rotation, 0.0f);
}
Vector3 targetDir = Quaternion.Euler(0.0f, _targetRotation, 0.0f) * Vector3.forward;
_characterController.Move(targetDir.normalized * _currentSpeed * Time.deltaTime);
//TODO:这里的Move可以执行垂直方向的速度,直接加上垂直的Vector就可以
}
}