- Home /
Raycast ignore itself
I've worked with Raycasts for a long time now, and I understand how it works with layermasks, etc...
But I have a problem right now that I couldn't find in any question here.
Let's say I have a sentry gun on a 2D game, which is rotating over time searching for the player. Each frame it tests with a raycast if it sees the player. This raycast is ignoring everything except the layer "Obstacle" which is used on objects which the player can't go through (It's a tile based game). The objects with that layer are the level walls, but also some "traps", and the sentry gun is one of them.
So my problem right now is that I want to shoot a raycast from the sentry gun, but the raycast is hitting the sentry itself, and I can't create a layer for all the obstacle "traps" and shoot a raycast ignoring everything except that layer because that way the player wouldn't be able to hide himself from sentrys behind other kind of "traps".
So right now I'm searching for a way of having a raycast ignore everything except 1 layer, and also ignore 1 object inside that layer.
PS: I know that I can use RaycastAll and then ignore this collider, but I am looking for a more efficient way if it exists.
Can't you add another layer like "Enemy" and make the turret be part of this layer?
That will fall into the problem where it will then ignore all the "Enemy" objects, which I don't want, because the player can hide from this "Enemy" behind any other "Enemy". If this makes any sense...
Then another layer called "Stationary_Enemy", just for turrets and objects alike, you can have as many as you want.
Ok let's say that I have Turret A and Turret B, I create a "Sationary_Enemy" layer and add it to both Turrets. The player is currently behind the Turret B when Turret A is ready to fire.
When Turret A casts it raycast ignoring the layer "Stationary_Enemy" it will ignore both Turret A and Turret B, which in this case (since the player is behind Turret B) will make Turret A fire a projectile even though it doesn't see the player.
You can have a secondary collider to shield the player, or start the raycast outside the turret mesh.
Answer by Yword · Jan 06, 2015 at 10:46 AM
Unity 4.6.1 has the option turn on/off the ability to detect a collider that overlaps the start of any 2D line/raycast in Edit -> Project Settings -> Physcis 2D -> Raycasts Start In Colliders.
As many upvotes as I can give for you sir. I spent days trying to figure out why my Raycasts returned themselves 80% of the time. I looked through so many different forum answers and everyone kept saying to start the Raycast outside of my bounds.
This answer needs to be propagated more, especially since Raycasts seem to work different (by default) between 2D and 3D.
Wow. I can't believe I didn't know that this entire time
erm i didnt mean to reply to you fattie just in general. Sorry
Answer by SilentSin · Jul 25, 2014 at 12:20 PM
I can see several possibilities:
Does the turret have any colliders on its children that are on the wrong layer?
Are you sure you're compiling the layer mask correctly? "~(1 << LayerMask.NameToLayer("Obstacle"))" would give you a mask of every layer except the obstacle layer.
Are you sure its hitting the turret and not something else? Try using Debug.Log(message, object), giving it the object you hit as the second parameter so that when you single click the log message in the editor, it will highlight that object in the hierarchy.
Are you sure you're casting the ray in the right spot? Try using Debug.DrawLine to draw the raycast in the scene view.
There isn't a way to have a raycast ignore a specific object unless you want to use RaycastAll (which you don't). There are valid use cases for RaycastAll, but this isn't one of them, the layer masking system should work.
How can the layer mask system work when I have two objects with the same layer, and I just want to ignore one of them without changing its layer? Please see the example I gave to Paulo Henrique.
Btw, I rewrote the question, I think it might have been misleading.
Your OP was a little unclear, the example clears it up a bit.
The layer mark system should still work as long as you are casting a ray from inside the collider of your turret, in which case the ray won't hit that collider, but it will still hit the other turret in front of the player.
If you have addressed all 4 things I suggested in my previous post, maybe you could post a screenshot of the scene view with the debug line in it so I can see where everything is located. Preferably with all of the objects in the scene selected so that I can see all the colliders.
1- The turret doesn't have any child object;
2- I'm casting the ray hitting only that layer, so at the moment I'm using this:
Physics2D.Raycast(transform.position, dir, dist, Layer$$anonymous$$ask.Get$$anonymous$$ask("Obstacle"));
3- Yes I made sure using the Debug.Log(message, object);
4- This was one of the first things I tested.
As I mentioned above I'm using the Raycast from Physics2D, and I didn't know it would ignore its own collider.
I didn't realise that you'd be using 2D physics. I would be using 2D for my current game if it had capsule colliders :(
I don't know if raycasting from inside a 2D collider ignores it like it would in 3D. It should be simple enough to test though. If that turns out to be your problem, you could just move the origin of the ray forwards a bit. So ins$$anonymous$$d of calling ...Raycast(transform.position, dir... you'd call ...Raycast(transform.position + dir, dir... or you could multiply dir by 0.5 or something if 1m might be too far forward.
What about disabling the collider of the turret when the ray starts and when it hits something you enable again? $$anonymous$$ind of hackish but could work.
Answer by Amit_B · Oct 25, 2014 at 05:45 PM
I had the same problem, this is how I solved it:
Physics2D.Raycast(rayCasterPosition + directionOfRayCast*this.collider2D.bounds.size.magnitude, directionOfRayCast, distance+1);
directionOfRayCast is normalized.
To put it more simply, I shot the ray outside of my own collider.
Answer by Pangamini · Mar 19, 2018 at 03:20 PM
Whenever I need to do some custom raycast collider filtering, I use RaycastNonAlloc (works for both 2D and 3D physics). It's actually RaycastAll but allows you to use pre-allocated array for results (for performance reasons).
The way how it works is that it returns all potential hits, and lets you select the one you like. The simplest usage would look like this: Collect all hits, sort them by distance. Go through them in the closest-to-farthest order, stop at the one that matches your criteria.
Don't be worried about the extra cost of collecting all hits. The physics engine has to do very similar thing when doing a regular Raycast anyway.
You can use this method to filter out collider hits based on anything where layers won't help, eg. texture alpha on the hit position (that's what I've been using it for, mostly)
Some extra tips:
Consider filtering out collisions before sorting (see what's more expensive, filtering or sorting in your use cases)
When sorting, don't even think about doing vector.magnitude! all you need is sqrMagnitude when comparing multiple vector lengths (as sqrt is an one-to-one function), you will save a lot of sqrt's which are quite expensive.
Answer by Tsilliev · Mar 19, 2018 at 12:28 PM
My solution was to turn off the collider before the raycast and turn it on at the end:
for (int i = 0; i < sectorCount; i++)
{
locations [i].GetComponent<CircleCollider2D>().enabled = false;
RaycastHit2D hit = Physics2D.Raycast (locations [i].transform.position, Vector2.up);
.
.
stuff
.
.
locations [i].GetComponent<CircleCollider2D>().enabled = true;
}
It's an interesting way to achieve it, but you have to consider the fact, that if your character is standing in an "isTrigger"-Collider from another object, that OnTriggerExit and OnTriggerEnter will be called every frame because of the removed and then added collider of your player.