Интерактивные панели на базе UI [FPS]

В разных шутерах, а особенно в ролевых играх, от первого лица. Можно встретить различные интерактивные панели, мониторы и прочие устройства, где можно получить какую-нибудь информацию, ввести код доступа, и прочее. В некоторых случаях, создать такой объект можно как обычную 3D модель, допустим, если это кодовый замок. Однако, если мы хотим, чтобы в нашей игре было, что-то наподобие компьютера, с которым игрок может взаимодействовать, тогда нам понадобятся возможности UI системы. Основные проблемы тут могут возникнуть с тем, как собственно создать такой объект и правильно его масштабировать в игровом пространстве.


Для начала, создадим Canvas, для взаимодействия в игре.

Интерактивные панели на базе UI [FPS]

Он должен быть в режиме World Space, затем нам надо выбрать ширину и высоту (разрешение) холста.

После, нужно масштабировать, например, если мы хотим сделать в игре монитор в метр по ширине.
Для этого напишем небольшой скрипт, который вешаем на наш холст.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(Canvas))]

public class CalculateCanvasScale : MonoBehaviour {

	[Header("Ширина в метрах:")]
	[SerializeField] private float widthInMeters = 1;

	public void Calculate()
	{
		Canvas target = GetComponent<Canvas>();

		if(target.renderMode != RenderMode.WorldSpace)
		{
			Debug.Log(this + " выбран неверный режим 'Render Mode' необходимо установить его в 'World Space'");
			return;
		}

		RectTransform tr = GetComponent<RectTransform>();
		float size = widthInMeters/tr.sizeDelta.x;
		tr.localScale = new Vector3(size, size, size);

		BoxCollider coll = GetComponent<BoxCollider>();

		if(coll == null)
		{
			BoxCollider box = gameObject.AddComponent<BoxCollider>();
			box.size = new Vector3(tr.sizeDelta.x, tr.sizeDelta.y, 1);
		}
		else
		{
			coll.size = new Vector3(tr.sizeDelta.x, tr.sizeDelta.y, 1);
		}
	}
}

Этот также добавит коллайдер на объект.

Кнопка для панели инспектора:

#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(CalculateCanvasScale))]

public class CalculateCanvasScaleEditor : Editor {

	public override void OnInspectorGUI()
	{
		DrawDefaultInspector();
		CalculateCanvasScale t = (CalculateCanvasScale)target;
		GUILayout.Label("Расчет масштаба холста:", EditorStyles.boldLabel);
		if(GUILayout.Button("Calculate")) t.Calculate();
	}
}
#endif

Просто кидаем в папку с остальными скриптами.

Если вы измените ширину или высоту Canvas, то нужно будет заново пересчитать масштаб.
То есть просто нажать кнопочку "Calculate" в инспекторе.

Курсор, это обычный спрайт на сцене:

Интерактивные панели на базе UI [FPS]

Параметр Order In Layer нужно поставить на максимальное значение, чтобы курсор был всегда поверх UI.

Теперь, скрипт который осуществляет взаимодействие с панелью:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InteractivePanel : MonoBehaviour {

	[SerializeField] private string targetTag = "GameController"; // тег интерактивных панелей в игре
	[SerializeField] private float distance = 3; // дистанция взаимодействия
	[SerializeField] private RectTransform playerAim; // UI мишень
	[SerializeField] private Transform playerCursor; // курсор (спрайт)
	private bool isMouse;

	void Start()
	{
		Cursor.visible = false; // скрываем системный курсор
		ResetMode();
	}

	void ResetMode()
	{
		isMouse = false;
		Cursor.lockState = CursorLockMode.Locked; // фиксируем системный курсор по центру экрана
		playerCursor.gameObject.SetActive(false);
		playerAim.gameObject.SetActive(true);
	}

	void LateUpdate()
	{
		RaycastHit hit;
		Ray ray = Camera.main.ScreenPointToRay(new Vector3(Screen.width/2, Screen.height/2, 0));
		if(Physics.Raycast(ray, out hit, distance))
		{
			if(hit.transform.tag == targetTag && Cursor.lockState == CursorLockMode.Locked)
			{
				isMouse = true;
				Cursor.lockState = CursorLockMode.None; // освобождаем курсор, чтобы взаимодействовать с UI
				playerCursor.gameObject.SetActive(true);
				playerAim.gameObject.SetActive(false);
			}
			else if(hit.transform.tag != targetTag && Cursor.lockState == CursorLockMode.None)
			{
				ResetMode();
			}
		}
		else
		{
			ResetMode();
		}

		if(isMouse) CursorControl();
	}

	// управление позицией и вращением курсора
	// так-же, функция нужна чтобы прятать его, если он уходит за границы UI панели
	void CursorControl()
	{
		RaycastHit hit;
		Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
		if(Physics.Raycast(ray, out hit, distance))
		{
			if(hit.transform.tag == targetTag)
			{
				playerCursor.gameObject.SetActive(true);
			}
			else if(hit.transform.tag != targetTag)
			{
				playerCursor.gameObject.SetActive(false);
			}

			playerCursor.position = hit.point;
			playerCursor.rotation = Quaternion.FromToRotation(-Vector3.forward, hit.normal);
		}
		else
		{
			ResetMode();
		}
	}
}

Здесь мы управляем курсором, как системным, так и спрайтовым.

Итак, посмотрим как это работает, качаем проект:

У вас нет доступа!
Тестировалось на: Unity 5.5.0

Комментариев 1

Офлайн
спс очень помогло ! я и не знаю что сказать!
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Дешевый хостинг
  • Яндекс.Метрика