@Ezekiel4
Охотник на пиратов

Как нажимать на кнопки в 3D?

В зоне видимости неподвижной камеры есть 4 кнопки. Кнопки предствляют собой обычные кубы с коллайдерами. Мышь не зафиксирована и используется для управления игрой. При нажатии на каждую из кнопок должно происходить разное событие.

625dabe6842cb221996534.png

На данный момент код такой (ниже). Работает только если камера вращается, а мышка в центре, а перед камерой находится тока "выстрела" луча. Как его переделать, чтобы он работал при неподвижной камере и подвижной мыши?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ButtonClick : MonoBehaviour {

	[SerializeField] private Transform aimPoint;
	[SerializeField] private float range;

	[SerializeField] private string leftRedTag;
	[SerializeField] private string leftWhiteTag;
	[SerializeField] private string rightRedTag;
	[SerializeField] private string rightWhiteTag;

	private void Update() {
		if (Input.GetMouseButtonDown(0)) {
			RaycastHit hit;
			if (Physics.Raycast(aimPoint.position, aimPoint.forward, out hit, range))
				OnButtonClick(hit.transform.gameObject.tag);
		}
	}

	private void OnButtonClick(string tag) {
		if (tag == leftRedTag) {
			// код левой красной кнопки
		} else if (tag == leftWhiteTag) {
			// код левой белой кнопки
		} else if (tag == rightRedTag) {
			// код правой красной кнопки
		} else if (tag == rightWhiteTag) {
			// код правой белой кнопки
		}
	}
}
  • Вопрос задан
  • 32 просмотра
Решения вопроса 1
K0TlK
@K0TlK
Буллю людей.
Ты делаешь рейкаст куда-то вперед от какого-то трансформа, а тебе нужно делать рейкаст в сторону курсора. Camera.ScreenPointToRay возвращает луч, который идет от камеры к месту на экране. Пример:
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity))
{
    Debug.DrawRay(hit.point, hit.normal * 10, Color.red, 10f);
}


И не надо так использовать тэги. Когда у тебя будет не 4 кнопки, а 40, то в методе OnButtonClick у тебя будет 40 условий? А если ты написал тэг с ошибкой, то будешь искать потом откуда ошибки валят? Выдели эти кнопки отдельно, получай нужный компонент при рейкасте и вызывай метод OnButtonClick уже у отдельного компонента.
public interface IButton
{
    public void OnClick();
}

public class YellowButton : IButton
{
    public void OnClick()
    {
        Debug.Log("Yellow");
    }
}

public class Example : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity))
            {
                if(hit.transform.TryGetComponent(out IButton button))
                {
                    button.OnClick();
                }
            }
        }

    }
}


Также, каждый компонент может иметь метод OnMouseDown, который вызывается, когда игрок нажимает на него. Можно создать компонент кнопки и при нажатии на него будет вызываться ивент, на который можно подписать нужные методы.
public class Button : MonoBehaviour
{
    public event Action ButtonPressed;

    private void OnMouseDown()
    {
        ButtonPressed?.Invoke();
    }

}

public class ButtonHandler : MonoBehaviour
{
    [SerializeField] private Button _button;

    private void OnEnable()
    {
        _button.ButtonPressed += DoStuff;
    }

    private void OnDisable()
    {
        _button.ButtonPressed -= DoStuff;
    }

    private void DoStuff()
    {

    }
}
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы