Создание кнопок, реализованных во время выполнения с помощью скрипта, имеет правильно объявленные функции onClick - PullRequest
0 голосов
/ 04 марта 2020

В моей программе я создаю экземпляры кнопок во время выполнения. Эти кнопки создаются на холсте. Они должны ссылаться на главный объект, автомобиль. Кнопки должны относиться ко всем частям автомобиля. Когда я нажимаю кнопку, я хочу, чтобы камера увеличивала правильную автомобильную часть. Кнопки имеют тот же текст, что и автомобильные детали. Поскольку они создаются из префаба кнопок в ресурсах во время выполнения, я не знаю, как его кодировать, где, если я нажимаю на него, он увеличивает правильную часть.

Моя первая попытка была прикрепить скрипт к сборному кнопку, чтобы при нажатии он читал свой собственный текст (потому что он захватывает текст от всех дочерних элементов в другом скрипте), а затем считывал весь дочерний текст, сравнивал и находил, где текст кнопки был так же, как текст дочерней части, тогда он будет захватывать этот дочерний GameObject и ссылаться на преобразование этого GameObject и преобразовывать камеру в местоположение.

Я могу преобразовать камеру и все, потому что я уже сделал это, используя raycast, чтобы щелкнуть автомобильную часть, но я просто не знаю, как назначить onClick для кнопок. Код должен быть многоразовым, поэтому я пытался спроектировать его так, чтобы его можно было использовать для любого объекта ...


Изображение машины инспектора и деталей Изображение инспектора и сценария, который создает экземпляры кнопок

Ниже приведена моя попытка решить эту проблему. Этот скрипт прикреплен к кнопке prefab ...

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

public class ifClickedZoomy : MonoBehaviour
{
    public GameObject objofparts;
    public GameObject cm;

    Button btn;
    string nameofobj;

    void start()
    {


        btn = this.GetComponent<Button>();
        btn.onClick.AddListener(going);
        btn.name = nameofobj;

        var temp = objofparts.gameObject.transform.Find(nameofobj);

        //btn.onClick.AddListener(delegate { Zoomy(temp); });
    }

    public void Zoomy(Transform target)
    {

        cm.transform.position = target.transform.position + Vector3.one * 0.5f;
        cm.transform.LookAt(target);
    }

    void going()
    {
        /*
        if(btn.GetComponentInChildren<Text>().text == "SkyCar")
        {
            GameObject target = GameObject.Find("SkyCar");
            Vector2 targpos = target.transform.position;

            cm.transform.position = targpos;
        }
        */
    }

}

1 Ответ

0 голосов
/ 04 марта 2020

Ваш префаб кнопки может иметь скрипт, уже прикрепленный к объекту кнопки. В этом сценарии у вас будет метод c publi ClickBehaviour(), который предварительно связан с OnClick.

Этот сценарий должен иметь метод delegate, который можно установить извне из метода, называемого SetClickBehaviour.

Делегат - это, в основном, переменная, в которой хранится функция с определенной сигнатурой. Таким образом, делегат void хранит функцию void. Вы можете назначить делегата определенной функцией. Когда вы вызываете делегат, как если бы он был реальной функцией, он фактически вызывает функцию, которую он хранит. Таким образом, вы можете поменять, какая функция на самом деле вызывается во время выполнения, изменив, какая функция хранится в делегате.

Таким образом, вы должны создать экземпляр префаба кнопки, а затем отправить ему поведение для связи с ним, вызвав newButton.SetClickBehaviour(methodToCall);

Так что SetClickBehaviour отвечает за изменение того, что хранится в делегате ..

Затем внутри ClickBehaviour вы вызываете метод делегата, который был установлен извне.

Итак, ClickBehaviour фактически вызывает этот делегат.

Button Spawner

using UnityEngine;

public class ButtonSpawner : MonoBehaviour
{

    // Button Prefab
    [SerializeField] 
    RuntimeButton RuntimeButtonPrefab = default;

    // Where to create instantiated buttons
    [SerializeField] 
    Canvas ParentCanvas = default;

    void Start()
    {
        //Create Buttons
        RuntimeButton newRuntimeButton1 = Instantiate(RuntimeButtonPrefab, ParentCanvas.transform);
        newRuntimeButton1.SetClickBehaviour(MethodThatButton1ShouldDo);

        RuntimeButton newRuntimeButton2 = Instantiate(RuntimeButtonPrefab, ParentCanvas.transform);
        newRuntimeButton2.SetClickBehaviour(MethodThatButton2ShouldDo);
    }

    //These methods could be anything and from any other scripts
    public void MethodThatButton1ShouldDo()
    {
        Debug.Log("Method for Button1 Worked!");
    }

    public void MethodThatButton2ShouldDo()
    {
        Debug.Log("Method for Button2 Worked!");;
    }


}

Button Script

using System;
using UnityEngine;

//This class is attached to button
public class RuntimeButton : MonoBehaviour
{
    //An action is just a kind of delegate.
    Action clickBehaviour;

    //This is called from another script to define what method gets called when button is clicked.
    public void SetClickBehaviour(Action someMethodFromSomewhereElse)
    {
        clickBehaviour = someMethodFromSomewhereElse;
    }

    // This is linked in button inspector to the OnClick event.
    public void ClickBehaviour()
    {
        clickBehaviour.Invoke();
    }

} 

В действии: enter image description here

Одна вещь, которую нужно отметить а также: в вашем обновленном вопросе ваш скрипт отвечает за несколько вещей: заставить кнопку слушать, найти часть, прослушать щелчки, переместить камеры и «уйти». Это слишком много для одного сценария! Хорошей идеей будет разделить эти идеи на разные сценарии, каждый из которых несет только одну основную ответственность. Я считаю, что это часто помогает диагностировать проблемы и может предложить возможные решения. В моих примерах сценариев RuntimeButton отвечает только за захват OnClick и вызов его делегата. Неважно, что делает этот делегат.

ButtonSpawner отвечает только за кнопки вызова. В реальной программе два метода, которые передаются кнопкам, будут определенно находиться в отдельных скриптах, так как они не имеют ничего общего с порождающими кнопками. Я просто положил их туда для этого минимального примера.

...