Is there no way to tell Unity to "give me collision information", but "do not interfere with my game objects' movement"?
As I explain in this answer, the contact information you get from collision events is generated as part of the collision resolution process, where the engine is figuring out how to change the positions and movements of the colliding objects to remove penetration.
That's costly extra work it doesn't need to do to simply detect overlaps, so if you haven't asked it to alter the objects' trajectories, then it doesn't do all this extra work, helping your game run faster.
And that's not a problem, because for the rare cases where we need contact information without altering motion, we can get that through other means: the rich set of raycasting and shape-casting methods the physics engine gives us.
So, we can keep our moving object (or its obstacle) as a trigger collider, to save the costly collision resolution work and avoid fighting with the engine to undo it. Then we can use a script to fire shape casts to reconstruct the impact normal when we detect a new trigger overlap.
Here's an example of how we could do that with a circular body. Here I assume the circle is centered on the object's origin, but we can adapt this to work with off-center colliders too.
[RequireComponent(typeof(CircleCollider2D), typeof(Rigidbody2D)]
public class TriggerEdgeDetector : MonoBehaviour {
public LayerMask layersToDetect;
public UnityEvent<Vector2> OnHitWithNormal;
Vector2 _oldPosition;
CircleCollider2D _collider;
Rigidbody2D _body;
void Awake() {
_collider = GetComponent<CircleCollider2D>();
_body = GetComponent<Rigidbody2D>();
}
void FixedUpdate() {
_oldPosition = _body.position;
}
void OnTriggerEnter2D(Collider2D other) {
Vector2 travel = _body.position - _oldPosition;
var hit = Physics2D.CircleCast(
_oldPosition,
_collider.radius,
travel,
travel.magnitude,
layersToDetect);
if (hit && (OnHitWithNormal != null))
OnHitWithNormal.Invoke(hit.normal);
}
}