Radical Bowling – Scripting Dynamic Friction

TL, DR; This is how I add dynamic friction to the bowling ball over time.

When I first started working on this project I was doing some reading on bowling lanes. It turns out that they lanes have oil on them. The exact placement and pattern of the oil depends on the alley, lane, and event but that is not important to my game. This oil pattern is what causes the bowling ball to do that weird (and awesome) sliding thing, where the ball seems to roll backwards in some cases. I wanted to simulate this in my game so I tried a few things.

The first thing that I tried was just making the ball slippery. I make a physics material for the ball and set the dynamic friction to zero. The result was a really unnatural effect that looked more like the ball was being dragged down the lane. Not what I’m going for.

Next I added a physics material to the lane as well. With both the lane and ball having zero dynamic friction I had a really slippery ball. In fact, at this point I could bowl strikes without the ball ever starting to roll. It would just slide all the way down the lane.

Then I had what I thought was a great idea. I would use two colliders. In Unity, physics materials are a property of a collider, so I thought that adding two colliders would give me the effect I wanted. This approach did work but it had a some drawbacks. For one, all balls stopped sliding at the exact same distance down the lane. It looked OK at first but after bowling a few frames people would start to notice. Another drawback was that using two colliders started to interfere with other scripts and logic throughout the game. For example, I’m using OnCollisionStay to change the volume and pitch of the ball rolling sound and leaving the first collider would terminate the rolling sound.

I was thinking aloud about this problem on VR Hermits when I started to wonder if I could actually change the physics material at runtime. Yes, yes I can. Below is the solution that I came up with today. It’s not perfect and I’m sure I’ll need to make adjustments over time, but this is far better than anything I’ve tried so far. Basically I just made a coroutine that will adjust the friction over time. First I add a bunch of friction all at once and then I Lerp the rest on with the time remaining.


using UnityEngine;

public class BallController : MonoBehaviour {

    public float frictionDelay = 0.8f;
    public float frictionTarget = 0.4f;
    private PhysicMaterial pm;

    private void Awake()
    {
        pm = GetComponent().material;
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.tag == "Floor")
        {
            StartCoroutine(AdjustFriction(frictionDelay));
        }

    }

    IEnumerator AdjustFriction(float time)
    {
        // Start by waiting half of the delay time
        yield return new WaitForSeconds(time / 2);

        // We are going to SLAM on some friction using a number between zero anbd half of the target friction
        pm.dynamicFriction = Random.Range( 0.0f, frictionTarget / 2);


        // Then we are going to Lerp our way to the target friction with the time left
        float currentTime = 0.0f;
        do
        {

            pm.dynamicFriction = Mathf.Lerp(pm.dynamicFriction, frictionTarget, currentTime / (time / 2));
            Debug.Log(pm.dynamicFriction.ToString());
            currentTime += Time.deltaTime;
            yield return null;

        }
        while (pm.dynamicFriction < frictionTarget);
    }

}

You may also like...