Detecting when the player stops casting to IRaycastable?

Hi all,
Trying to add some more interface functionality for my project and decided I want to make AI Conversants (and other interactable components) highlighted when I raycast them.

I can’t seem to figure out a way in the IRaycastable interface to detect when the raycast has stopped.

I’ve added the following method to HandleRaycast in my AI Conversant (though I might just make a new component with IRaycastable for it called Highlighter or something):

		private void HighlightComponent()
		{
			if (meshRenderer != null && meshRenderer.materials.Length > 1)
			{
				meshRenderer.material = meshRenderer.materials[1];
			}
		}

So part 1 works great for turning it on, but it won’t switch back because I need to call the material change again.
What is the right way to do this?

The only place that handles when the casting stops is player controller Update() method (for cursors),
Other place I could think of is the components own Update() method,
but I don’t think I should check it every frame. or should I?
And i’m still not sure about how to detect when the raycast stopped

Current player controller Update():

private void Update()
		{
			CheckSpecialAbilityKeys();
			if (InteractWithUI())
			{
				SetCursor(CursorType.UI);
				return;
			}

			if (health.IsDead())
			{
				SetCursor(CursorType.None);
				return;
			}

			if (InteractWithComponent()) return;

			if (InteractWithMovement()) return;

			SetCursor(CursorType.None);
		}

Would very much like to learn any good way to detect the frame in which the raycast stopped hitting the IRaycastable?
Or Am I going about it the wrong way?
Should I make a IHighlightable interface and check for that in the player controller?

(I am following the 4 sections of course project so the main parts of my code are the same as at the end of Dialogue&Quests).

It’s easy to find the objects that the raycast hits, it’s less easy to find the objects that the raycast doesn’t hit.

There are several ways I can think of right now that this can be done;

  • Reset the material in Update, or
  • Start a coroutine that resets it after 0.1f seconds, and stop/restart the routine on every highlight, or
  • Keep a list of highlighted objects and track whether or not they are still being hit. If not, reset

The first two methods are much the same; just let the object assume it should be in the default state, the raycast will highlight it again - in that same frame, hopefully - and it will be fine.

The third assumes nothing and you need to have a list of all the objects you highlighted before, add new ones that’s not there, and reset and remove ones you are no longer hitting.

I have not touched these courses in a while, so I am quite rusty on their functionality. Maybe there’s a simpler way already built in, but I can’t remember that there is

I would say this is the ideal one:

Coroutine resetRoutine;
IEnumerator ResetMaterialRoutine()
{
    yield return new WaitForSeconds(.01f);
    ResetMaterial(); //Call this when done
    resetRoutine= null;
}

In HighlightComponent, start with

if(resetRoutine!=null) StopCoroutine(resetRoutine);
resetRoutine = StartCoroutine(ResetMaterialRoutine);

Yup, just like that. I use similar ‘start-and-interrupt’ coroutines for other things, too. And I recently discovered you can stop an Invoke, too, but I almost never use Invoke

@bixarrio @Brian_Trotter
Thank you both! :pray: :pray:

I ended up first implementing your solution, which works perfectly.
Then I decided to try OnMouseOver and OnMouseExit, works just as well.
Are there any benefits or drawbacks to using one or the other?

I honestly haven’t done a comparison of the performance of OnMouseOver/Stay/Exit vs a Ray Trace. One would presume that the Event System’s raycaster is just broadcasting these events to any object if runs over (if it has them defined). The savings, if any, may just be because the EventSystem is already doing the RayTrace, so why do it again.

A few caveats, though… RayTraces allow us to get an actual Hit.Point, which could be utilized, if we wrote for it, to get even more granular with our approaches. For example, you could leverage a variation of HandleRaycast that also takes in a point to make the terrain itself an IRaycastable, which would call the MoveAction (or even grants a better affordance by putting a 3d marker where you click!).

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms