Contacts Modification API in Unity

Dmitry Gordeev
WaveAccess
Published in
4 min readJul 4, 2022

In most cases, the capabilities of standard physics are enough for the implementation of everything that you need. But sometimes, you need more options to create a different behavior when objects collide.

For these particular cases, Unity Technologies allows modifying contacts of collided objects starting from version 2021.2.

The On Contact Event

To work with contacts you need to define a callback which will be called when the physics system is ready to process the contacts.

The callback for the contact modification event

The next step is to add this callback to the ContactModifyEvent.

Add the callback

Now you can enter Play Mode, and detect that your callback is not called. It happens because the physics system doesn’t allow you to modify all contacts by default. So we need to set the hasModifiableContacts for the colliders we want to modify.

Set the flag to make the contacts modifiable

Modifiable Contact Pair

The callback has a parameter with the type NativeArray<ModifiableContactPair>. It is an array of contact pairs. Each pair contains information about positions, rotations, velocities, etc. It also contains methods to modify some of them.

Please note that it doesn’t guarantee that the desired collider will be the main one and the second one will be the “other”. So you need to check both to find the one you need to change (or it’s better to create a helper class).

A full description of properties and methods is in the official Unity documentation.

Use cases

I want to share with you examples of what you can create using the new contacts modifications API.

Conveyor

Let’s start with moving objects along some surfaces. Conveyors in games are not the same things as in real life. The conveyor belt is usually just a moving texture. So how can it move objects? I’ll explain.

The ModifiableContactPair contains the method SetTargetVelocity that can be used to set velocity as the target for the physics system (for its part called the solver). It is what we exactly want to do — to set the velocity for the objects on the conveyor.

Let’s start with defining the necessary fields.

The necessary fields

The Physics.ContactModifyEvent is not linked to the MonoBehaviour where it is added, so you need to be able to determine that event fired for a specific object. For this purpose we will use the instance ID of the Rigidbody added to the GameObject.

Convert the velocity and store the body ID

The final step is the callback itself. So what we need to do is to check that contact points are on our GameObject and set the target velocity to these points.

Set target velocity

I use 3 objects, 2 straight lines, and 1 corner. Don’t forget to add a kinematic rigidbody and a collider to objects.

Example of the conveyor
Example of the conveyor

One direction pass

Another example is an object that passes objects in one direction and blocks them in the other.

The Awake method is almost the same as in the previous example.The difference is in the callback method. We need to check that the pass direction and a moving object (we will use the normal of the contact point) are co-directed. To check it we can use the vector operation called “dot product” and if the dot product is greater than 0 — the vectors are co-directed.

Check the direction

And the result is a platform that passes objects moving upwards.

one direction pass object
Example of the one direction pass object

You can change the example to pass objects with a specific speed (velocity) or use any other condition.

Contacted face (triangle)

Additional information which you can get from the ModifiableContactPair is the face index in the mesh that contains the contact point.

Necessary fields for example

The ConcurrentDictionary will be used as ConcurrentHashset (because it doesn’t exist in the System.Collections.Concurrent we will use the dictionary instead).

You can use an imported mesh or you can generate it. I have generated a uniform grid mesh for the example in the GenerateMesh method (the result is equal to the Create->Plane GameObject’s menu).

The next step is to create the callback for the ContactModifyEvent.

Store the contacted faces

As you may have noticed, we do not do anything with pairs. We store them as a key in the dictionary (the value is just a dummy value). The reason is the callback can be called from any thread, not just in the main thread so many operations with Unity’s API are not allowed. We will process them in the FixedUpdate method.

Process contacted faces

We remove touched faces and update the mesh. Also, you can add some VFX or particles to make it feel breakable.

Contacted face example
Remove contacted faces

Conclusions

The examples above are just a few things you can create with the contacts modifications API. You are limited only by your imagination.

Please leave a comment below, and let me know how you work with a new access to low level physics API.

--

--