Как стать автором
Обновить

Управление персонажем, с помощью мыши в Unity

Стандартные Asset управления в Unity имею несколько скриптов, перемещение только с помощью клавиатуры и клавиатуры и мыши, но отсутствует скрипт перемещения с использованием мыши («Diablo-style»). Скрипты будет написаны на C#.

image



Для проверки всего, что будет написано, понадобятся сцена и размещенные на ней объекты. Их всего 4, это: Персонаж (я использовал: Standard Assets -> Character Controllers -> 3rd Person Controller), Камера, Объект выполняющий роль Цели, я использовал капсулу, можно использовать просто пустой объект, если вы не хотите видеть куда идет ваш персонаж, и Terrain по которому мы и будем перемещаться. Рассмотрим с начало скрипт Камеры.

using UnityEngine;

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));
}

void Update() {
if (!onPlace) {
// Вычисляем вектор перемещения
direction = target - this.transform.position;
// Нормализуем, что бы персонаж смотрел не в землю, а прямо
direction = new Vector3(direction.x, 0, direction.z);
direction.Normalize();

// Поворачиваемся
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 GetTarget(Vector3 target) {
// Проверим позицию Target
if ((Mathf.Abs(transform.position.x - target.x) >= radiusNoClick) &&
(Mathf.Abs(transform.position.z - target.z) >= radiusNoClick))
{
this.target = target;
// Скажем что персонаж не на месте
onPlace = false;
}
}

public void OnPlaceTrue() {
onPlace = true;
}
}


Метод GetTarget() принимает из скрипта MouseCamera позицию цели и проверяется не находится ли он около персонажа. Если все хорошо и цель далеко, персонаж начинает движение в сторону цели, путем вычислений проводящихся в Update(). Метод OnPlaceTrue() служит для указания персонажу, что он на месте. Он используется в небольшом триггере который размещается на объект Цели.

using UnityEngine;

public class TriggerOnTarget : MonoBehaviour {

public MousePerson player;

void OnTriggerEnter(Collider onPlace) {
player.OnPlaceTrue();
}
}


При пересечении зоны триггера, сообщается что персонаж прибыл в место назначения.

image

В коллайдере необходимо указать что "он" триггер, установить радиус (зависит от размеров вашего персонажа) и указать в скрипте персонажа, от которого он зависит.
У персонажа в скрипте все настройки оставлены по умолчанию, и ничего дополнительного указывать нет необходимости.
image
На камере в скрипте необходимо указать объект который выполняет роль цели, игрока которым управляет и слой который будет "ловить" клики, и по которому будет ходить персонаж. Для этой цели я завел отдельный слой Terrain и присвоил его объекту выполняющему роль земли.
Вот и все, пробуйте и экспериментируйте.

Исходники и тестовая сцена тут.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.