CameraRaycaster script - don't see the layers

Hello,

I don’t see the layers at CameraRaycaster script, as shown at lecture 46 sec. 2

Why?

Hi,

Bit of a guess here, as you’ve not given a lot of info to go by (screenshots/code examples etc), but, do you have the Utility.cs file in your Assets folder? This is the script which the layers are defined in as an enum.

Hope this helps :slight_smile:

Well no I don’t.
At the start of the lecture or the one befor it, the instructor deleted the script file, so I did the same…

Hi,

Ok, so that’s good to know. From memory, some of that enum, gets written into another script doesn’t it, have you added that? (CursortAffordance.cs).

I’ve checked everything again according to lectures 46, 47 sec. 2 and couldn’t find any diffrences.

Here is CursorAffordance.cs:

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

[RequireComponent(typeof(CameraRaycaster))]
public class CursorAffordance : MonoBehaviour
{
    
    [SerializeField] Texture2D walkCursor = null;
    [SerializeField] Texture2D unknownCursor = null;
    [SerializeField] Texture2D targetCursor = null;

    [SerializeField] Vector2 cursorHotspot = new Vector2(0, 0);

    [SerializeField] const int walkableLayerNumber = 8;
    [SerializeField] const int enemyLayerNumber = 9;

    CameraRaycaster cameraRaycaster;

    // Use this for initialization
    void Start()
    {
        cameraRaycaster = GetComponent<CameraRaycaster>();        
        cameraRaycaster.notifyLayerChangeObservers += OnLayerChanged;        
    }

    void OnLayerChanged(int newLayer)
    {
        print("Cursor over new layer");
        switch (newLayer)
        {
            case walkableLayerNumber:
                Cursor.SetCursor(walkCursor, cursorHotspot, CursorMode.Auto);
                break;            
            case enemyLayerNumber:
                Cursor.SetCursor(targetCursor, cursorHotspot, CursorMode.Auto);
                break;
            default:
                Cursor.SetCursor(unknownCursor, cursorHotspot, CursorMode.Auto);
                return;
        }
    }
}

And, here is CameraRaycaster.cs :

using UnityEngine;
using UnityEngine.EventSystems;
using System.Linq;
using System.Collections.Generic;

public class CameraRaycaster : MonoBehaviour
{
	// INSPECTOR PROPERTIES RENDERED BY CUSTOM EDITOR SCRIPT
	[SerializeField] int[] layerPriorities;

    float maxRaycastDepth = 100f; // Hard coded value
	int topPriorityLayerLastFrame = -1; // So get ? from start with Default layer terrain

	// Setup delegates for broadcasting layer changes to other classes
    public delegate void OnCursorLayerChange(int newLayer); // declare new delegate type
    public event OnCursorLayerChange notifyLayerChangeObservers; // instantiate an observer set

	public delegate void OnClickPriorityLayer(RaycastHit raycastHit, int layerHit); // declare new delegate type
	public event OnClickPriorityLayer notifyMouseClickObservers; // instantiate an observer set


    void Update()
	{
		// Check if pointer is over an interactable UI element
		if (EventSystem.current.IsPointerOverGameObject ())
		{
			NotifyObserersIfLayerChanged (5);
			return; // Stop looking for other objects
		}

		// Raycast to max depth, every frame as things can move under mouse
		Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
		RaycastHit[] raycastHits = Physics.RaycastAll (ray, maxRaycastDepth);

        RaycastHit? priorityHit = FindTopPriorityHit(raycastHits);
        if (!priorityHit.HasValue) // if hit no priority object
		{
			NotifyObserersIfLayerChanged (0); // broadcast default layer
			return;
		}

		// Notify delegates of layer change
		var layerHit = priorityHit.Value.collider.gameObject.layer;
		NotifyObserersIfLayerChanged(layerHit);
		
		// Notify delegates of highest priority game object under mouse when clicked
		if (Input.GetMouseButton (0))
		{
			notifyMouseClickObservers (priorityHit.Value, layerHit);
		}
	}

	void NotifyObserersIfLayerChanged(int newLayer)
	{
		if (newLayer != topPriorityLayerLastFrame)
		{
			topPriorityLayerLastFrame = newLayer;
			notifyLayerChangeObservers (newLayer);
		}
	}

	RaycastHit? FindTopPriorityHit (RaycastHit[] raycastHits)
	{
		// Form list of layer numbers hit
		List<int> layersOfHitColliders = new List<int> ();
		foreach (RaycastHit hit in raycastHits)
		{
			layersOfHitColliders.Add (hit.collider.gameObject.layer);
		}

		// Step through layers in order of priority looking for a gameobject with that layer
		foreach (int layer in layerPriorities)
		{
			foreach (RaycastHit hit in raycastHits)
			{
				if (hit.collider.gameObject.layer == layer)
				{
					return hit; // stop looking
				}
			}
		}
		return null; // because cannot use GameObject? nullable
	}
}

Thanks for the help.

Just a query are you using 2018 and have you changed walkableLayerNumber in unity?
In later versions of unity layer 8 is taken by post processing so i moved my layer numbers in case of a confliction.

I doubt this is the issue but if you want post processing effects later i would keep layer 8 as the post processing. (If you have it in your version)

So is the print statement being called? (“Cursor over new layer”)?

If thats not being called the issue is in the delegates probably

It might be good to get a little clarity on the issue here also, for example you say you dont see the layers but could you, in more depth explain what is/isn’t happening, e.g “When I move the mouse over X and right-click…” that kinda of thing.

On that note, the code above doesn’t have the if statement which checks for a right-click - might be in a subsequent video.

Also, as the call to NotifyObserersIfLayerChanged (deliberate mis-spelling) relies on the EventSystem perhaps double-check you have an EventSystem GameObject in your Hierarchy.

To clarify - the problem is:
On main camera => Camera Raycaster (Script) : don’t see the layers under “Layer Priorities” as shown in lectures 46, 47 Sec. 2 (I see only size)

1 Like

I do use version 2018.2.2f1

The statement - “Cursor over new layer” does being called.

1 Like

I do have EventSystem GameObject in the hierarchy. As was instructed on lec. 46…

1 Like

Thanks for the replies and further information, that’s really useful.

So, it sounds as if then you don’t have any layers in the array, or, that they are all the default layer as you haven’t been able to set/change them. So even if the code is all correct, the iterations that take place which then trigger the notification of observers don’t happen because you are iterating through an empty array.

Just to check, you are saying you don’t have the layers appearing in the Inspector, perhaps like this;

image

Assuming this is the case, have you added the CameraRaycasterEditor.cs script to the Editor folder within Assets? If so, can you copy/paste your script for that into your reply also please.

The picture you pasted describes the problem.
Here is the code for CameraRaycasterEditor.cs :

using UnityEditor;


// TODO consider changing to a property drawer
[CustomEditor(typeof(CameraRaycaster))]
public class CameraRaycasterEditor : Editor
{
    bool isLayerPrioritiesUnfolded = true; // store the UI state

    public override void OnInspectorGUI()
    {
        serializedObject.Update(); // Serialize cameraRaycaster instance

        isLayerPrioritiesUnfolded = EditorGUILayout.Foldout(isLayerPrioritiesUnfolded, "Layer Priorities");
        if (isLayerPrioritiesUnfolded)
        {
            EditorGUI.indentLevel++;
            {
                BindArraySize();
                BindArrayElements();
            }
            EditorGUI.indentLevel--;
        }

        serializedObject.ApplyModifiedProperties(); // De-serialize back to cameraRaycaster (and create undo point)
    }

    void BindArraySize()
    {
        int currentArraySize = serializedObject.FindProperty("layerPriorities.Array.size").intValue;
        int requiredArraySize = EditorGUILayout.IntField("Size", currentArraySize);
        if (requiredArraySize != currentArraySize)
        {
            serializedObject.FindProperty("layerPriorities.Array.size").intValue = requiredArraySize;
        }
    }

    void BindArrayElements()
    {
        int currentArraySize = serializedObject.FindProperty("layerPriorities.Array.size").intValue;
        for (int i = 0; i < currentArraySize; i++)
        {
            var prop = serializedObject.FindProperty(string.Format("layerPriorities.Array.data[{0}]", i));
            prop.intValue = EditorGUILayout.LayerField(string.Format("Layer {0}:", i), prop.intValue);
        }
    }
}

Also it’s true that in runtime I see only the unknowncursor. So you correct by mentioning that the layers are all default layer (the icon doesn’t change).

Thanks for posting this. From memory this script is provided and you didn’t need to type this yourself etc.

One thing though, as an editor script it will only execute if it is in a folder named Editor within the Assets directory. Can you confirm this to be the case?

Yes, it is.
And I only imported it, didn’t change a thing. It is in the EDITOR folder.

Ok, thanks for confirming.

Now, lets check your layers. Can you select any GameObject in the Hierarchy (doesn’t matter which), and then expand the Layer drop down within the Inspector and confirm that you have the ones required, e.g.;

image

Yes, confirm.

Ok, let’s check that CameraRaycasterEditor.cs script again, just for test purposes, add the following directive to the top of the script;

using UnityEngine;

and then within the OnInspectorGUI method, add a line at the top of that method as follows;

Debug.Log("OnInspectorGUI was called");

Leave the rest of the code as is, save the file. You’ll see the Unity editor re-compiling the code (bottom right corner of Unity).

Once it has done this, select the Main Camera GameObject in the Hierarchy, under Camera Arm, and view the Inspector. This should then execute the above method, and if you switch to the Console you should see the output. Note, it will only count up whilst you view the Main Camera in the Inspector.

Do you get this output in the console?

You can undo these changes afterwards, they are not needed after this point.

the USING is there

Doing the rest…wait…pls

I get this error message :
Assets/Editor/CameraRaycasterEditor.cs(12,9): error CS0103: The name `Debug’ does not exist in the current context

Privacy & Terms