I have the code checked for if it is null.
(Sorry for the bad formatting, I will correct that)
Code for my ProcessMovement:
[RequireComponent(typeof (NavMeshAgent))]
[RequireComponent(typeof (AICharacterControl))]
[RequireComponent(typeof (ThirdPersonCharacter))]
public class PlayerMovement : MonoBehaviour {
AICharacterControl aiCharacterControl = null;
ThirdPersonCharacter thirdPersonCharacter = null; // A reference to the ThirdPersonCharacter on the object
CameraRaycaster cameraRaycaster = null;
Vector3 currentDestination; // required so we don't start moving in some arbitray direction or start moving, until we actually click.
private bool isInDirectMode = false; //TODO Consider making static later if other scripts
//require this information.
void Awake()
{
cameraRaycaster = Camera.main.GetComponent<CameraRaycaster>();
cameraRaycaster.notifyMouseClickObservers += ProcessMouseClick;
}
void Start()
{
thirdPersonCharacter = GetComponent<ThirdPersonCharacter>();
currentDestination = transform.position;
aiCharacterControl = GetComponent<AICharacterControl>();
}
void ProcessMouseClick(RaycastHit raycastHit, int layerHit)
{
print("Click");
}
//TODO Make this get called again
void ProcessDirectMovement()
{
Debug.Log("In direct movement mode");
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
// calculate camera relative direction to move:
// calculate move direction to pass to character
Vector3 cameraForward = Vector3.Scale(Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized;
Vector3 movement = v * cameraForward + h * Camera.main.transform.right;
thirdPersonCharacter.Move(movement, false, false);
}
}
The CameraRaycaster script is as follows:
public class CameraRaycaster : MonoBehaviour
{
// INSPECTOR PROPERTIES RENDERED BY CUSTOM EDITOR SCRIPT
[SerializeField] int[] layerPriorities; // int value based, compared to OLD with layer types
float maxRaycastDepth = 100f; // Hard coded value
int topPriorityLayerLastFrame = -1;
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 and store in array named 'raycastHits', 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; // Too many Dots!
NotifyObserersIfLayerChanged(layerHit);
// Notify delegates of highest priority game object under mouse when clicked
if (Input.GetMouseButton (0))
{
if (notifyMouseClickObservers != null)
{
Debug.Log(priorityHit.Value);
Debug.Log(layerHit);
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;
}
}
CursorAffordance Script:
[RequireComponent (typeof(CameraRaycaster))]
public class CursorAffordance : MonoBehaviour {
[SerializeField] Texture2D walkCursor = null;
[SerializeField] Texture2D targetCursor = null;
[SerializeField] Texture2D unknownCursor = null;
[SerializeField] Vector2 cursorHotspot = new Vector2(0 , 0); // The actual clicking point on the cursor
//TODO solve fight between serialize and const
[SerializeField] const int walkableLayerNumber = 9;
[SerializeField] const int enemyLayerNumber = 10;
[SerializeField] const int deadLayerNumber = 11;
CameraRaycaster cameraRaycaster;
void Start() {
cameraRaycaster = GetComponent<CameraRaycaster>();
cameraRaycaster.notifyLayerChangeObservers += OnLayerChangeForCursor; // Registering to oberver list.
}
// Only called when layer changes.
void OnLayerChangeForCursor(int newLayer) {
switch (newLayer) // Used to say "switch (cameraRaycaster.currentLayerHit)" before we passed parameters with delegates.
{
case walkableLayerNumber:
Cursor.SetCursor(walkCursor, cursorHotspot, CursorMode.Auto);
break;
case enemyLayerNumber:
Cursor.SetCursor(targetCursor, cursorHotspot, CursorMode.Auto);
break;
default:
//Debug.LogError("Don't know what cursor to show");
Cursor.SetCursor(unknownCursor, cursorHotspot, CursorMode.Auto);
return;
}
}
}
Thank you so much. I know this is a lot.