- Home /
2D Colliders stops working at random despite rigidbody, OnMouseDown not called
I did a one day project to clone the solitare game from Shenzhen I/O to prepare for making another game. However at random times cards cannot be picked up. I'd like to understand the root of the problem and how I can fix it or do better, not alternative ways of making a card game (as I intended to carry things over to more complex games with scrolling world spaces).
What I have are:
Objects with a 2D collider component, most are playing cards using the box 2d collider
Colliders are set as triggers
These objects have a RigidBody2D component with body type set to Kinematic
OnMouseDown/OnMouseDrag/OnMouseUp are used to drag and drop cards
transform.position is set to move cards during dragging, Z order (and sprite order) is adjusted as needed
transform.SetParent is called to attach cards together when laid partially on top of each other
What I'm experiencing is at random times (maybe 1 out of 200) a card will become stuck - it no longer fires the OnMouseDown method when clicked and debugging shows that ray casting doesn't see the collider. Inspection shows coordinates and parent/child values are correct and the problem can be "fixed" by disabling the object and then enabling it again while the game is still playing in the editor.
This seems entirely like the behavoir expected when moving static colliders which I see a lot of questions about, but I was under the impression that if I added a kinematic rigid body that I could then move the object by setting transform.position and the colliders would be properly updated. Ultimately I need to be able to click or determine what is under a point in world space reliably, with some objects having more complex shapes (circle or polygon colliders). No physics are wanted.
No physics are wanted. This seems entirely like the behavoir expected when moving static colliders which I see a lot of questions about, but I was under the impression that if I added a kinematic rigid body that I could then move the object by setting transform.position and the colliders would be properly updated.
If no physics are wanted then why are you using physics objects? $$anonymous$$oving a static collider just seems like being rebelious for no reason; it's static for a reason ... you don't intend to move it. There are no problems "expected" at all with Static colliders. Add a $$anonymous$$inematic body when you intend to move it; add a Static body (or no body) if you don't intend to move it ... simple. Why is it such a problem adding a $$anonymous$$inematic body? I only ask because it's done time and time again, not adding a Rigidbody component due to some misconception.
Here's the rule: You should never ever move colliders, full stop. If you want to move colliders then attach them to a body and move that. Even if you only want to use the collider for collision-detection and not response this is true. I can only presume this is what you mean by "No physics are wanted". Collision detection is obviously physics.
Also note that the On$$anonymous$$ouse, OnXXX are all UI things. They all use the Physics2DRaycaster (a UI class) which itself uses Physics2D.GetRayIntersectionNonAlloc (a 2D Physics method). If you want to perform your own and much more efficient tests then you can use the 2D physics intersection tests yourself such as the Physics2D.OverlapPointNonAlloc call.
If no physics are wanted then why are you using physics objects
If you know of a way to perform world space hit tests in Unity without reinventing the wheel please say so. As far as I can see, and if you know differently why don't you post it as an answer and get some rep, Unity's mouse handling for world space objects is riding on the physics system with no clear way to seperate the two.
$$anonymous$$oving a static collider just seems like being rebelious for no reason; it's static for a reason
Which is why I'm not moving a static collider. I stated in my post at least 3 times, including in the title that I was using rigid bodies. I've stated that I'm already aware that moving static colliders is bad and that I'm not doing it. I'm repositioning kinematic rigidbodies, which all documentation I've been able to get so far says is correct, and yet I'm still experiencing collider bugs.
As for perfor$$anonymous$$g my own intersection tests, well I already am (to deter$$anonymous$$e what I've dragged over). I didn't mention that explicitly but I did state clearly that I had performed manual ray casting when I tried to debug the issue and the colliders where still not visible - in other words doing my own ray casts will not help if the rigidbody/collider has decided to stop working. The ray casting is not the issue, it's the collider disappearing or being misplaced on whatever optimized tree Unity has going on behind the scenes.
I am not here to argue with you or to try to get some rep. I didn't have an answer that is a solution for you so I just added a comment which is what comments are for. You end simply with 'No physics are wanted. ' and many users refer to this as meaning they don't want movement. It is impossible to know whether you knew this or not. You know what you know, unfortunately I don't.If you know of a way to perform world space hit tests in Unity without reinventing the wheel please say so. As far as I can see, and if you know differently why don't you post it as an answer and get some rep, Unity's mouse handling for world space objects is riding on the physics system with no clear way to seperate the two.
For some reason I completely missed the above. I am still urked at myself for missing that. $$anonymous$$aybe I need new glasses or more sleep.These objects have a RigidBody2D component with body type set to $$anonymous$$inematic
aYou're experiencing bugs, not necessarily collider bugs. When it doesn't work, have you checked that the collider gizmo is still rendering at the position you expect it to be? That indicates that the collider is not only there but that the underlying physics system has collision shape(s) at that position. I will also reiterate that it might be worth using OverlapPoint rather than raycast as (from what I can imagine), you're not actually perfor$$anonymous$$g a ray-cast, you're looking for an intersection in Z (a ray-cast of zero length). An overlapPoint might provide you with a better check.nd yet I'm still experiencing collider bugs.
btw: If there's any way, whether that be automated or not that you can duplicate this situation then please submit it as a bug.
When I've been able to encounter this bug and inspect it in the editor the colliders where where they where supposed to be (both in the live game tab using gizmos to visualize colliders and on the scene editor tab where I selected the individual collider). Of course those lines are debug lines, likely drawn using the public collider data and not whatever optimized cache Unity has behind the scenes.
The idea that the colliders might be misplaced due to my own code is also less likely due to the fact that toggling the game object (unchecking its active checkbox and then checking it again) instantly fixes the issue without any other changes to the objects properties. I've also compared things like the info section for the rigidbodies, to see if there was something unusual about the sleep state or other values but it was identical to working cards.
As for reproduction that's really what drove me to see if anyone could provide insight. The rarity (most I've had are two stuck cards in a single game and many games have none) of the bug appearing has made it extremely difficult to deter$$anonymous$$e if a given piece of code triggers it. If I remove or change anything the only way to test if it had any effect is to play a lot of games, over and over again, until I either encounter the bug or I am forced into 'assu$$anonymous$$g' that the bug is gone, which given that it's likely a race condition of some sort is a really bad assumption. It's just as likely that I've only made it harder to trigger which is not a solution.
At the moment I am still trying to make a $$anonymous$$imal scene, object and code wise, that I can trigger the bug with but have been unsuccessful so far, whether because I haven't introduced the cause of the bug or because I haven't played the scene enough to randomly stumble on it I don't know.
Note: I'm the 2D physics dev for Unity.
I can say with authority that for this very reason, we use the b2Shape data from Box2D (the 2D physics engine behind the scenes) to draw the gizmos. The gizmos are not draw using the public properties that define colliders i.e. box size etc. If the gizmo is there, so is the physics shape in the 2D physics system. Now I'm really confused as to why it's intermittent apart from there being an issue with the UI events themselves but you say that the debug raycast you perform confirms there collider isn't there. This goes against everything I know as the gizmo is there therefore the shape is there. This would suggest that your debug code suffers from the same problem as the UI events. I cannot suggest more strongly that you use a simpler debug check such as OverlapPointXXX as I suggested previously. Obviously that needs to work all the time before you get the problem. Although I doubt this is the issue, are you using an orthogonal camera set-up? What version of Unity are you using? Could you back-up your project and try 5.6-beta to see if the problem still exists?Of course those lines are debug lines, likely drawn using the public collider data and not whatever optimized cache Unity has behind the scenes.
would suggest that your debug code suffers from the same problem as the UI events
This statement got me thinking along the right track and was extremely helpful along with the other statements about what should and should not be possible with the raycast and trying other debug checks. I went back and redid all my debugging code from scratch (originally I took the raycast call from the card drop script and had it run every frame where the cursor was with the result logged to the console) and I think I've found my problem, the table.
By taking my debug code from the card handler it wasn't picking up the table and some other factors (like sprite rendering being seperate from Z ordering and the table extending beyond the screen) helped camouflage the true problem, an instance where cards could wind up with the exact Z value of the table. The apparent randomness was simply the undefined nature of such a tie. When comparing working and not working cards I couldn't see any difference because the working cards where equally wrong and I just didn't know it.
Oddly I went back to the project I did the day before, a chess game, because I had recycled pretty much the same code for the board/table and ordering sprites on top of it. The bug was worse there (the pieces almost always wound up with the same Z coordinate as the board) yet I hadn't encountered any issues. $$anonymous$$y only guess as to why it didn't fail much sooner is that once the parent was initially set on the chess pieces it wasn't being changed, while the cards frequently had their parent property juggled. This would also explain the red herring that disabling and reenabling an object 'fixed' it.
I've made changes that I believe fix the condition that led to the Z coordinate going too far and added an assertion to trigger a warning if it still happens. With that sorted out I can look at using OverLap testing since it looks like it can completely replace the types of ray casts I need to do. When you suggested OverlapPointNonAlloc am I right in assu$$anonymous$$g it's because OverlapPoint may allocate memory even though it only needs to return 1 element?
Reading the documentation for OverlapPointNonAlloc I get the impression that the return value may be greater then the size of the results array, signalling that the method should be called again with a bigger array, and that there is no defined order for the entries in the results array - if I only need the element with the smallest Z value I need to ensure I used a large enough array to get all of them and then search the array myself.