Curious Fixation: Mining for reusable code


This is the second in a series of postmortems where I will be evaluating my previous projects. Curious Fixation is the second (released) project I worked on as a solo programmer in Unity, and was completed as a part of a game jam in 2018 in conjunction with artist Peter Cowen. Peter and I have also worked together on The Monkey Way and Search and Rescue as a part of a larger team. You can find Peter on Artstation at this link.

Interpolation

Before beginning the process of producing a lightning effect during gameplay, I did not know how to go about simulating the sequence of pulses associated with a strike. I briefly investigated the generation of peaks/troughs and interpolating between during a strike before discovering that particles in Unity can be linked to light probes, the technique used in Curious Fixation. The resulting effect was considered good enough to move forward at the time, but that brief period researching how I might use interpolation to tweak the values at runtime during the scene stayed with me for some time after the project, as it seemed clear that it was functionality that I could use on a regular basis. I could use DoTween or another external tool, but I was looking for something lightweight, and wanted to learn for myself how I might implement the technique. 

Ideally, I would be able to pass an arbitrary property by reference to a coroutine along with a target value and a runtime and Mathf.Lerp could do the rest. During research, I came across this Unity answer as well as this other Unity answer

 // inputDelegate assumed form: coroutineOutput => result = coroutineOutput
 public static IEnumerator FloatCoroutine(Action<float> inputDelegate, 
                                             float start, float target, float runtime) {
        float nextValue = 0f;
        float startTime = Time.time;
        float endTime = startTime + runtime;
        float runtimeReciprocal = 1 / runtime;
        while (Time.time < endTime) {
            nextValue = Mathf.Lerp(start, target, (Time.time - startTime)* runtimeReciprocal);
            inputDelegate(nextValue);
            yield return null;
        }
        nextValue = target;
        inputDelegate(nextValue);
    }

I've placed my IEnumerator inside a custom static class, and run the coroutine inside an arbitrary script like so:

float resultStorage;
StartCoroutine(Interpolate.FloatCoroutine(x=> resultStorage = x, 0f, 10f, 10f);

Delegates and lambda expressions allows coroutines to effectively write to variables by reference under certain conditions - no refin or out. Unfortunately this restriction is currently preventing me from modifying a generic lambda expression by substitution and obtaining Interpolate(start, end, time) but it is very close. Before examining the coroutine path, I had used a pattern similar to that used in PerformLerp below, executed in the Update method of a custom script.

    public float PerformLerp(ref float elapsed, float a, float b, float runtime)
    {
        elapsed += Time.deltaTime;
        if (elapsed >= runtime)
        {
            return b;
        }
        else
        {
            return Mathf.Lerp(a, b, elapsed / runtime);
        }
    }

To be continued...

Get Curious Fixation: An Infinite Runner

Download NowName your own price

Leave a comment

Log in with itch.io to leave a comment.