private void OffsetFoot(int limbIndex)
    {
        //Offsets foot by basically taking half a step

        FootIKTarget footIKTarget = footIKTargets[limbIndex];

        Vector3 referencePosition = stableFeetPositions[limbIndex];

        //Decide where to step
        RaycastHit nextStep;
        Vector3    raycastOrigin = referencePosition + transform.forward * stepStride / 2 + transform.up * 100;
        bool       foundStep     = Physics.Raycast(raycastOrigin, Vector3.down, out nextStep);

        if (!foundStep)
        {
            return;
        }

        footIKTarget.position = nextStep.point;

        BodyControl();
    }
    private void MoveFoot(int limbIndex, float time)
    {
        FootIKTarget footIKTarget = footIKTargets[limbIndex];       // select the foot we are trying to control

        Vector3 referencePosition = stableFeetPositions[limbIndex]; // get the grounded position of that foot

        //Decide where to step using raycast
        RaycastHit nextStep;
        Vector3    raycastOrigin = referencePosition + transform.forward * stepStride + transform.up * 100;
        bool       foundStep     = Physics.Raycast(raycastOrigin, Vector3.down, out nextStep);

        if (nextStep.point.y - referencePosition.y > maxStepHeight)
        {
            raycastOrigin = referencePosition + transform.up * stepStride - transform.forward * 100;
            foundStep     = Physics.Raycast(raycastOrigin, transform.forward, out nextStep);
        }

        if (!foundStep)
        {
            return;
        }


        /****NOTE!!! The rest of this function is just to control the animation. I did a lot of work to get a nice animation which you can AVOID!****/
        /***You could just use Vector3.MoveTowards() to move the feet like in the simpler alternative I worte below to save you from a lot of trouble****/

        //*** The simpler alternative code *** P.S. I didn't design the system for this, so the animation looks a bit weird, but technically, it works!

        //if (time > 0)
        //{
        //    if (time < 0.1f)
        //    {
        //        footIKTarget.position = referencePosition + Vector3.up * 0.2f;
        //    }
        //    else
        //    {
        //        footIKTarget.position = Vector3.MoveTowards(footIKTarget.position, nextStep.point, Time.deltaTime * 5);
        //        if (time == 1) footIKTarget.position = nextStep.point;
        //    }
        //}


        //*** The more complex but better looking animation code ***///

        //Obtain the non-animated world step
        Vector3 worldStepVector         = nextStep.point - referencePosition;
        float   horizontalStepMagnitude = new Vector2(worldStepVector.x, worldStepVector.z).magnitude;

        //Convert world step vector to a local step vector with local forward direction as reference forward direction
        float stepAngleOffset = Vector2.SignedAngle(new Vector2(worldStepVector.x, worldStepVector.z),
                                                    new Vector2(transform.forward.x, transform.forward.z));
        Vector3 localStepVector = new Vector3(Mathf.Sin(stepAngleOffset * Mathf.Deg2Rad) * horizontalStepMagnitude,
                                              worldStepVector.y, Mathf.Cos(stepAngleOffset * Mathf.Deg2Rad) * horizontalStepMagnitude);


        //Sample animation curves taking note of the limb side. *The animation curves are designed with the world forward direction as reference forward direction
        int     sideSign     = footIKTarget.limbSide == LimbSide.Left ? 1 : -1;
        Vector3 stepProgress = new Vector3(stepCurveX.Evaluate(time) * sideSign, stepCurveY.Evaluate(time), stepCurveZ.Evaluate(time));
        Vector3 stepOffset   = new Vector3(stepOffsetCurveX.Evaluate(time) * sideSign, stepOffsetCurveY.Evaluate(time), stepOffsetCurveZ.Evaluate(time));

        // The commented out code below simply enables the step spheres and lines you see in the video

        //if (stepProgress.magnitude > 1.5f)
        //{
        //debugLine.SetPosition(0, raycastOrigin);
        //debugLine.SetPosition(1, nextStep.point);
        //debugSphere[0].gameObject.SetActive(true);
        //debugSphere[0].position = nextStep.point;
        //}

        //if (t == 0 || t == 1)
        //{
        //    debugSphere[limbIndex].gameObject.SetActive(true);
        //    debugSphere[limbIndex].position = footIKTargets[limbIndex].position;
        //}

        //compute the animated step vector from the local step vector
        Vector3 animatedLocalStepVector = Vector3.Scale(localStepVector, stepProgress) + stepOffset;

        float animatedHorizontalStepMagnitude = new Vector2(animatedLocalStepVector.x, animatedLocalStepVector.z).magnitude;
        float animationAngleOffset            = Vector2.SignedAngle(new Vector2(animatedLocalStepVector.x, animatedLocalStepVector.z),
                                                                    new Vector2(localStepVector.x, localStepVector.z));

        //Obtain the angle between the world forward direction and the local forward direction
        float forwardAngleOffset = Vector2.SignedAngle(new Vector2(transform.forward.x, transform.forward.z), Vector2.up);

        float totalAngleOffset = stepAngleOffset + animationAngleOffset + forwardAngleOffset;

        Vector3 animatedWorldStepVector = new Vector3(Mathf.Sin(totalAngleOffset * Mathf.Deg2Rad) * animatedHorizontalStepMagnitude,
                                                      animatedLocalStepVector.y, Mathf.Cos(totalAngleOffset * Mathf.Deg2Rad) * animatedHorizontalStepMagnitude);

        footIKTarget.position = referencePosition + animatedWorldStepVector;

        BodyControl();
    }