I’m trying to make a character that can go on walls, for that the player changes it’s Rigidbody’s up direction to match the normal of the surface it’s walking on and if it’s touching multiple surfaces then use the average of their normals. For surface detection i’m using both OnCollisionEnter and OnCollisionStay. This works fine until the character stands near the edge of a ramp which mesh is non-convex, in that case a ghost collision appears at the very edge and since there’s two collisions the Rigibody’s up direction is set to the average of their normals. The strange part is that this only occurs if the mesh is non-convex or if using a Capsule Collider, using a convex one or using a Sphere Collider fixes the problem but this isn’t convenient for level design nor player collisions. Is there a way around this so i can use non-convex meshes?
It’s strange that the issue only happens on capsules…
It’s possible to have multiple colliders on a gameObject which means you could have a capsule collider for the upper section of your character and a sphere collider at the bottom.
Thanks for the idea, it’s what i ended up doing. I had some complications tho, because i wanted to have all my colliders in objects that are inside a empty child to keep things organized but then i couldn’t access the collider i was gonna use for surface detection. I researched a bit and found a solution that uses Physics.ContactEvent, which is the event that collects all the contact pairs (which are collisions between two colliders) that will be feed to the FixedUpdate. I’ll put the code i used here for people that may need it.
public class YourClass : MonoBehaviour
{
[SerializeField] public Collider surfaceDetector; //Set the collider you want to use in the inspector.
private int colliderInstanceId; //This will be the ID stored in memory of the desired collider.
void Awake(){
surfaceDetector.providesContacts = true; //Needed to be able to see ContactPairs that the desired collider is in.
colliderInstanceId = surfaceDetector.GetInstanceID(); //Store the ID of your desired collider.
Physics.ContactEvent += RetrieveColliderPairs; //Subscribe your function or unsubscribe it if not using the event.
}
void OnDestroy(){
Physics.ContactEvent -= RetrieveColliderPairs;
}
void OnEnable(){
Physics.ContactEvent += RetrieveColliderPairs;
}
void OnDisable(){
Physics.ContactEvent -= RetrieveColliderPairs;
}
private void RetrieveColliderPairs(PhysicsScene scene, NativeArray<ContactPairHeader>.ReadOnly contactPairHeader){
foreach (ContactPairHeader header in contactPairHeader){ //Retrieves every ContactPairHeader from the array.
for (int i = 0; i < header.pairCount; i++){
ContactPair pair = header.GetContactPair(i); //Retrieves every ContactPair from each ContactPairHeader.
if ((pair.colliderInstanceID == colliderInstanceId) && (pair.isCollisionEnter || pair.isCollisionStay)){
YourFunction(pair); //If the pair is from the desired collider and type of OnCollision
} //call (Enter, Stay, Exit), pass it to your function.
}
}
}
private void YourFunction(ContactPair pair){
//Put your code here...
}
}
Hello, could you elaborate what “YourFunction(pair);” would be? I am having the same issue with a box collider, i just want it to stop getting snagged on ground vertices. It’s frustrating.
The function just filters collisions of the colliders i want to have info of, using their collider instance ID. I did this because of the bug i described in the first post with specifically the capsule collider. I don’t see how could this solve your problem since you’re not using the same collider type. Maybe your problem has something to do with a case like this (see image), where you have several colliders next to each other and your character “catches” on the edges. I haven’t solved this problem because it can be avoided by keeping these cases at a minimum. I suggest you to search more about “ghost collisions” on forums or youtube tutorials, that’s what people refer to your problem.

