Limiting A Raycast To A Single Object

Say I have a door with a collider attached to it that triggers the opening and closing of the door. Additionally, I have a character object behind that door that has a collider attached to him which triggers dialog.

At the moment, when I touch the door, it responds correctly - opens, closes, reports locked, etc - however, the touch also passes through the door and triggers the dialog with the character.

How do I set things up so that the ray can only touch the character if the door is first moved out of the way (i.e. by opening it)?

just add a variable on the character that checks if the door is open before firing the dialogue

or use layers to raycast only the door

Layers don’t really help here though do they? Because the ray only applies to a certain layer, but both object are still going to receive the “touch” on their collider.

Using a variable is what I’m doing at the moment, but it’s a total mess because there are many doors and many objects behind them. If it was just a once off, it would work fine.

I’m now thinking about just using a shorter ray length on the door collider code… actually no, that won’t work either.

Is there no way to just tell a ray to stop once it’s hit the first object in its path?

you cant set your player to ignore raycast layer ?

or set a layer mask when you raycast, you define a layer for your door and make your ray check only for object be in that layer…that work, but after if you use the ray for other purpose it may not be ideal

or if you you cant go layer mask road, i would put an ID on your object door, and just send an event to play yoru door stuff, in fact you cut your process, your ray no matter what check against all collider , then you just send back an event with the ID took from the collider,

in your door stuff listen for it, if the ID define a door then do your door stuff, or just nothing…

well just suggestion…hope that can help to work around your issue :slight_smile:

Maybe it’s my limited understanding of raycasting that’s the problem :frowning:

Say I have a script attached to the door called “door_control”. I also have a script attached to the character called “character_control”.

BOTH of those scripts have this code in them to trigger their function:

function Update()
{
	var ray : Ray = Camera.main.ScreenPointToRay(Input.mousePosition);
	var hit : RaycastHit;
	if (collider.Raycast(ray, hit, 5))
	{
		if (Input.GetButtonDown("Fire1"))
		{
			// open the door, close the door, etc in door_control
			
			// initiate dialog in character_control
		}
	}
}

Because this is triggered by a touch (in this case, as it’s an iPhone game), it doesn’t matter if the two objects have separate layer masks for the raycast, because they’ll both still be “hit” by the single touch on screen…

…right?

Yeah the ID thing is essentially what I’m doing now with the “variable” method discussed earlier.

I thought there just might be an easy way to send a ray that stops once it hits it’s first object.

you should fire your ray only when you get a touch event, and with a Physics.Raycast() fonction using layer mask no matter what you input you will check with the ray itself not the touch…i may not be super sure on how behave your game tho, but i would do opposite check for fire button then throw a ray to check what i hit, but that may not suit your situation

Hmm… I’m not even sure that will do it though.

I’m now thinking maybe I add some additional code to the character_control script that uses a Physics.Linecast to determine if the collider for the door is “in the way” before it executes it’s code. Don’t know. That feels messy. Can’t be worse than the mess I have right now though with door IDs.

I’ll play and post back with results. If anyone else has suggestions please let me know though.

Thanks for the thoughts giyomu :slight_smile:

That’s not an efficient way to do it, you’re firing a ray every frame for every object in your game? And all the same ray as well?

You should instead have a single function in your game that fires 1 ray if you press a button (not every frame)
Find what was hit using RaycastHit and then send a message to that object with SendMessage

That way the ray will only hit the top most object and not any others.

e.g.

function Update(){
   if(Input.GetButton("Fire1")){
        var ray : Ray = Camera.main.ScreenPointToRay(Input.mousePosition);
	var hit : RaycastHit;
	if (Physics.Raycast(ray, hit, 5))
	{
		if(hit.collider.name=="Door"){
                        hit.collider.SendMessage("OpenDoor");
                }
	}
   }
}

or simply have a single SendMessage(“Touched”) and have all your different scripts react to that message in the appropriate way

You can skip the check entirely and use Unity - Scripting API: SendMessageOptions.DontRequireReceiver
so that you can send the “Touched” message to every object that you raycast and don’t worry about there being no scripts on the walls to receive the message

@spinaljack - come on dude… where were you two years ago when I learnt all my Unity bad habits? :slight_smile:

So basically I’m doing it wrong. OK… I’ll redo it all over the long weekend and see if I can clean up my mess.

Thanks for the help. Appreciate the quick responses!

well spinaljack resume all that clearly ^^