I am creating a ground checker script and unfortunately it isn't detecting the ground when I am using a contact filter. m_groundChecker is a collider2D. Code (CSharp): private void GroundChecker() { m_isGrounded = false; Vector2 direction = Vector2.down; int count = m_groundChecker.Cast(direction, m_contactFilter, m_collisionCheck, .5f); hitList.Clear(); for (int i = 0; i < count; i++) { hitList.Add(m_collisionCheck[i]); //will only contain list of object hits } for (int i = 0; i < hitList.Count; i++) //looping through each hit to check normal and determine if grounded { Vector2 currentnormal = hitList[i].normal; Vector2 currentpoint = hitList[i].point; //int currentLayer = hitList[i].transform.gameObject.layer; if (currentnormal.y > minGroundNormalY) { m_isGrounded = true; m_groundNormal = currentnormal; break; } } } I attached a picture of my project settings, I am using layer "RayCastGroundCheck" As I understand, I should only be detecting collision with the ground, and platform layer although I'm not getting any detection at all. Please help!
You have `m_contactFilter` defined but where are you setting up any of its options? Read the docs: https://docs.unity3d.com/ScriptReference/ContactFilter2D.html You would need to call SetLayerMask on it first for it to filter your results by layer. So define a public or serialized LayerMask variable `groundLayers` and set it to your ground layers in the inspector, then pass that into `m_contactFilter.SetLayerMask(groundLayers)`
Also, if you want to use the layer collision matrix for any query you can also use Physics2D.GetLayerCollisionMask to retrieve the collision mask for the layer the collider is on. To get the layer the collider is on use GameObject.layer (the GameObject the Collider2D is on). As said above, you pass this mask to ContactFilter2D.SetLayerMask. Pseudo code: Code (CSharp): void Start() { // Set the filter for layers that collide with the GameObject layer. var collisionMask = Physics2D.GetLayerCollisionMask(gameObject.layer); m_contactFilter.SetLayerMask(collisionMask); }
Sorry I forgot to include that bit, I set up my contact filter in start. Here is the code Code (CSharp): protected void Start() { m_contactFilter.SetLayerMask(LayerMask.GetMask("Default")); m_contactFilter.useLayerMask = true; } Also I just realized I'm actually using the default layer not the ground check one but still I should be getting detection no?
The only reason I don't want to use the same layer my character is currently on, is because I plan on switching the players layer to interact with different environmental props. This is a good suggestion though, maybe I can use this as a work around.
You'll obviously get things that are on the default layer. Default isn't every layer. Note you can make the ContactFilter2D a public field and you can change it in the editor inspector. This is much easier than doing it in script.
The thing is I'm not currently getting any detection. The object my ground checker is on is a platform which is checked on the default layer, so I should be getting detections and therefore be grounded. However, it is showing no detection at all!? I'll switch to making the contactfilter2d a public variable, as suggested, and I'll let you know if that helps
You can use ContactFilter2D().NoFilter() to reset it so that it's not filtering at all. If you still don't detect something then it's not that you're filtering out stuff. A few other minor things relate to code you've posted. When using the methods to set filter contents like SetLayerMask, you don't need to activate the option separately on as it'll be activated for you as it mentions in the docs. Also, you're using the Collider2D.Cast method then transferring the results to a list but depending on what version of Unity you're using, there's overloads for all queries that take (and reuse) generic list results so you can get the results directly in a list.
I used ContactFilter2D().NoFilter() right before I called m_groundChecker.Cast() and I am getting detection now. Not sure what to do now though since this means I'm just detecting everything right? In other words it is equivalent to calling Collider2D.Cast() without a contact filter at all? The whole point of the contact filter is to only detect collisions of a particular layer. So this indicates my contact filter is set up incorrectly no? Also side note, you've been fantastic help and I appreciate you taking the time to help me!
Yep, indicates you're not setting the layer-mask correctly or the object(s) you want are not on those layers. I presume you've not tried setting the contact filter to be a public field yet and setting the layer mask there.
You presume correctly, I haven't tried making it public yet. I guess I'm just confused because I thought the way I set it up in start was correct. Could it be that these two lines are not doing what I thought? Code (CSharp): m_contactFilter.SetLayerMask(LayerMask.GetMask("Default")); m_contactFilter.useLayerMask = true;
It takes a few seconds to do this and just verify in the inspector that your code is doing what you think it's doing. It takes much longer to engage in a forum thread. Personally I wouldn't ever have these hard-coded strings in my project, they're prone to error and if you decide to change a name then they stop working. But to answer your question then yes, the code above sets the filter to only allow the layer "Default" through and you don't need to explicitly set the "useLayerMask" to true either as it's set for you when you set the layer mask.