Pull to refresh

Управление персонажем, с помощью мыши в 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 и присвоил его объекту выполняющему роль земли.
Вот и все, пробуйте и экспериментируйте.

Исходники и тестовая сцена тут.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.