Unity: для доступа к нестатическому члену требуется ссылка на объект — Рэй приводится к GameObject

Я делаю игру в стиле RTS, и у меня есть ошибка. Я пытаюсь отправить текущий выбранный юнит (объект, на котором находится скрипт) в FSM Playmaker объекта, на который попал raycast. Я понял, что вы не можете получить доступ к игровым объектам и преобразованиям внутри статической функции, поэтому я попытался вызвать другую функцию, чтобы использовать хит и заполнить переменную игрового объекта.

Это ошибка:

Assets/Scripts/Unit.cs(57,41): error CS0120: An object reference is required to access non-static member `Unit.SetOurObject(UnityEngine.RaycastHit)'

Основная проблема, я думаю, здесь:

public static Vector3 GetDestination()
    {
        if (moveToDestination == Vector3.zero)
        {
            RaycastHit hit;
            Ray r = Camera.main.ScreenPointToRay(Input.mousePosition);

            if (Physics.Raycast(r, out hit))
            {
                while (!passables.Contains(hit.transform.gameObject.name))
                {
                    if (!Physics.Raycast(hit.transform.position, r.direction, out hit)) //point + r.direction * 0.1f
                        break;
                }
                //gameObject.GetComponent<NavMeshAgent>().SetDestination(hit.point);
                //if (hit.transform != null){
                //print (hit);
                if (resources.Contains(hit.transform.gameObject.name)){
                    SetOurObject(hit);
                    //SelectedUnit.Value = GameObject.name;
                    //ResourceHit.Fsm.Event("startHit");
                } else {
                    moveToDestination = hit.point;
                }
                //}
            }
        }
        return moveToDestination;
    }

    public void SetOurObject(RaycastHit hitRay) 
    {
        ourObject = hitRay.transform.gameObject;
        PlayMakerFSM ourFSM = ourObject.GetComponent<PlayMakerFSM>();
        FsmGameObject SelectedUnit = ourFSM.FsmVariables.GetFsmGameObject("SelectedUnit");
        SelectedUnit.Value = new GameObject();
        ourFSM.Fsm.Event("ResourceHit");
    }

А вот и весь скрипт:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using HutongGames.PlayMaker;

public class Unit : MonoBehaviour {

    public PlayMakerFSM ResourceHit;
    public GameObject ourObject;

    public bool selected = false;
    private Color SelectedCol = new Color(0.114f, 0.22f, 0.039f, 1.0f);
    private Color UnselectedCol = new Color(0.357f, 0.604f, 0.184f, 1.0f);

    private bool selectedByClick = false;

    private Vector3 moveToDest = Vector3.zero;

    private static Vector3 moveToDestination = Vector3.zero;
    private static List<string> passables = new List<string>() { "Floor" };
    private static List<string> resources = new List<string>() { "Res_Wood" };

    // Update is called once per frame

    private void CleanUp()
    {
        if (!Input.GetMouseButtonUp(1))
            moveToDestination = Vector3.zero;
    }

    private NavMeshAgent agent;
    void Start() {
        agent = GetComponent<NavMeshAgent>();
    }

    public static Vector3 GetDestination()
    {
        if (moveToDestination == Vector3.zero)
        {
            RaycastHit hit;
            Ray r = Camera.main.ScreenPointToRay(Input.mousePosition);

            if (Physics.Raycast(r, out hit))
            {
                while (!passables.Contains(hit.transform.gameObject.name))
                {
                    if (!Physics.Raycast(hit.transform.position, r.direction, out hit))
                        break;
                }
                if (resources.Contains(hit.transform.gameObject.name)){
                    SetOurObject(hit);
                } else {
                    moveToDestination = hit.point;
                }

            }
        }
        return moveToDestination;
    }

    public void SetOurObject(RaycastHit hitRay) 
    {
        ourObject = hitRay.transform.gameObject;
        PlayMakerFSM ourFSM = ourObject.GetComponent<PlayMakerFSM>();
        FsmGameObject SelectedUnit = ourFSM.FsmVariables.GetFsmGameObject("SelectedUnit");
        SelectedUnit.Value = new GameObject();
        ourFSM.Fsm.Event("ResourceHit");
    }

    void Update () {
        CleanUp();
        if (this.GetComponent<Renderer>().isVisible && Input.GetMouseButton(0))
        {
            if (!selectedByClick){
                Vector3 camPos = Camera.main.WorldToScreenPoint(transform.position);
                camPos.y = CameraOperator.InvertMouseY (camPos.y);
                selected = CameraOperator.selection.Contains(camPos);
            }
                if (selected)
                    this.GetComponent<Renderer> ().material.color = UnselectedCol;
                else
                    this.GetComponent<Renderer> ().material.color = SelectedCol;
        }
        if (selected && Input.GetMouseButtonUp(1))
        {
            Vector3 destination = GetDestination();

            if (destination != Vector3.zero)
            {
                gameObject.GetComponent<NavMeshAgent>().SetDestination(destination); //all you need if you have unity pro
                //moveToDest = destination;
                //moveToDest.y += floorOffset;
            }
        }
    }

    private void OnMouseDown()
    {
        selectedByClick = true;
        selected = true;
    }

    private void OnMouseUp()
    {
        if (selectedByClick)
            selected = true;

        selectedByClick = false;
    }
    }
    }

Заранее спасибо! знак равно


person 4t0m1c    schedule 27.02.2015    source источник
comment
Не используйте тег Unity для вопросов, связанных с игровым движком Unity3d. Для этого есть тег unity3d.   -  person Max Yankov    schedule 03.03.2015
comment
Извиняюсь за это, я не понял   -  person 4t0m1c    schedule 03.03.2015


Ответы (2)


Несмотря на то, что Кристос прав насчет why, он выдает исключение (вы пытаетесь получить доступ к методу экземпляра, как если бы это был статический метод), он упускает одну деталь.

В Unity3D вы не можете (легко) создавать экземпляры классов, реализующих MonoBehaviour. Вы создаете их, присоединяя компонент сценария к существующим игровым объектам, а затем можете ссылаться на них в коде.

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

Простой пример, предположим, что компонент сценария Unit прикреплен к тому же GameObject, вы ссылаетесь на него следующим образом:

Unit unit = GetComponent<Unit>();
// now we can call instance fields/properties/methods on this specific instance!
person walther    schedule 02.03.2015

Из полученного сообщения об ошибке видно, что метод

SetOurObject(UnityEngine.RaycastHit)

не является методом static класса Unit.

Следовательно, вы должны сначала создать экземпляр этого класса, а затем вызвать этот метод.

// I don't know exactly the signature of the constructor class
// If it is parameterless or not etc.
// So you have to correct it correspondingly, If I am wrong.
var unit = new Unit();

Затем вы можете вызвать метод, используя этот объект.

unit.SetOurObject(UnityEngine.RaycastHit);
person Christos    schedule 27.02.2015
comment
Спасибо за быстрый ответ, простите за нубство, но не могли бы вы объяснить это в терминах ламена. Чего достигает класс Unit? - person 4t0m1c; 27.02.2015
comment
Добро пожаловать, чувак. Без проблем. Конечно, насколько я понимаю, SetOurObject — это метод класса Unit. Правильный? Если это так, как кажется, и учитывая тот факт, что это не метод static, вы можете использовать его так: Static.SetOurObject(UnityEngine.RaycastHit), как мы делаем в случае метода WriteLine класса Console, Console.WriteLine. Мы должны сначала создать экземпляр класса Unit, а затем вызвать для этого объекта этот метод. Теперь это более понятно? - person Christos; 27.02.2015
comment
Хорошо, это помогает, спасибо .. Хотя это не помогает .. Может ли функция vector3 «GetDestination» быть динамической функцией, а не статической, и как? Я вижу проблему в том, что статическая функция не позволяет мне преобразовать хит в игровой объект. - person 4t0m1c; 27.02.2015
comment
@JaredBrandjes метод в С# принадлежит либо экземпляру класса, либо классу. В первом случае он называется методом экземпляра и может использоваться, как я указал выше. В то время как во втором случае это статический метод, и его можно использовать, просто используя имя класса и имя метода ClassName.Method(). Насколько мне известно, нет никакой концепции динамического метода. Итак, если ваш вопрос заключается в том, можете ли вы изменить GetDestination с static на нестатический метод экземпляра, мой ответ - да. Вы можете сделать это, если это соответствует вашим потребностям. - person Christos; 27.02.2015