0

I'm making an RTS style game and i've got an error. I'm trying to send the current selected unit (the object the script is on) to the Playmaker FSM of the object the raycast hit. I realised that you cannot access gameobjects and transforms inside of a static function so I tried to call another function to use the hit and fill the gameobject variable.

This is the error:

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

The main issue I think is here:

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");
    }

And here is the whole script:

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;
    }
    }
    }

Thanks in advance! =)

Max Yankov
  • 12,551
  • 12
  • 67
  • 135
4t0m1c
  • 329
  • 1
  • 7
  • 20

2 Answers2

3

Even though Christos is right about why it throws an exception (you're trying to access an instance method as if it was a static method), he's missing one detail.

In Unity3D you can't instantiate (easily) classes that implement MonoBehaviour. You create them by attaching a script component to existing gameobjects and then you can reference them in the code.

So to solve this, if you want to call that method, you have to first get a reference to the attached script component that's in the Scene and then you can do it.

Simple example, let's say the script component Unit is attached to the same GameObject, you reference it like this:

Unit unit = GetComponent<Unit>();
// now we can call instance fields/properties/methods on this specific instance!
walther
  • 13,466
  • 5
  • 41
  • 67
0

From the error message you got, it is clear that the method

SetOurObject(UnityEngine.RaycastHit)

is not a static method of the class Unit.

Hence, you have first create an instance of this class and after this call this method.

// 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();

Then you could call the method using this object.

unit.SetOurObject(UnityEngine.RaycastHit);
Christos
  • 53,228
  • 8
  • 76
  • 108
  • Thanks for the quick response, forgive my noobness, but could you explain it in lamens terms. What does the Unit class achieve? – 4t0m1c Feb 27 '15 at 07:40
  • You welcome dude. Not a problem at all. Of course, as I understand the `SetOurObject` is a method of the `Unit` class. Correct? If so, as it seems to be, and given the fact that is not a `static` method, you can use it this way: `Static.SetOurObject(UnityEngine.RaycastHit)`, like we do in case of `WriteLine` method of `Console` class, `Console.WriteLine`. We have first to create an instance of the class `Unit` and then call on this object this method. Is that more clear now? – Christos Feb 27 '15 at 07:43
  • Ok that helps, thanks.. It's not helping though.. Could the vector3 function 'GetDestination' be a dynamic function rather than static and how? I see the problem as being that the static function isn't allowing me to convert the hit into a gameobject.. – 4t0m1c Feb 27 '15 at 07:56
  • @JaredBrandjes a method in c# belongs either in the instance of a class or in the class. In the first case, it is called an instance method and can be used as I pointed above. While in the second case, it is a static method and can be used, using simply the name of the class dot the name of the method `ClassName.Method()`. There isn't any concept of dynamic method as far as I am aware of. So, if your question is if you can change the `GetDestination` from `static` to non static, to an instance method, my answer is yes. You can do so, provided that suits your needs. – Christos Feb 27 '15 at 08:02