Distance Matching Locomotion : Giving it a shot!

Hi guys! I planned to share my solution, but I have no time to complete it, so I’m here to share a part of my solution. Many people ask me how I get time by distance from curve. Code below is not perfect, but I’m not a C++ programmer :slight_smile: This code works only if you compress curve with “Uniform Indexable” compression type!



#include "Animation/AnimInstanceBase.h"
#include "Animation/AnimCurveCompressionCodec_UniformIndexable.h"

DEFINE_LOG_CATEGORY(LogAnimInstanceBase)

float UAnimInstanceBase::GetCurveTime(const UAnimSequence* *AnimationSequence*, const FName *CurveName*, const float *CurveValue*)
{
    if (AnimationSequence == nullptr)
    {
        UE_LOG(LogAnimInstanceBase, Error, TEXT("Invalid Animation Sequence ptr"));
        return 0.0f;
    }

*    // Get curve SmartName*
    FSmartName CurveSmartName;
    AnimationSequence->GetSkeleton()->GetSmartNameByName(USkeleton::AnimCurveMappingName, CurveName, CurveSmartName);

*    // Create a buffered access to times and values in curve*
    const FAnimCurveBufferAccess CurveBuffer = FAnimCurveBufferAccess(AnimationSequence, CurveSmartName.UID);

*    // The number of elements in curve*
    const int NumSamples = static_cast<int>(CurveBuffer.GetNumSamples());
    const int LastIndex = NumSamples - 1;

    if (NumSamples < 2)
    {
        return 0.0f;
    }

*    // Corner cases*
    if (CurveValue <= CurveBuffer.GetValue(0))
    {
        return CurveBuffer.GetTime(0);
    }
    if (CurveValue >= CurveBuffer.GetValue(LastIndex))
    {
        return  CurveBuffer.GetTime(LastIndex);
    }

*    // Binary search*
    int32 NextIndex = 1;
    int32 Count = LastIndex - NextIndex;
    while (Count > 0)
    {
        const int32 Step = Count / 2;
        const int32 Middle = NextIndex + Step;

        if (CurveValue > CurveBuffer.GetValue(Middle))
        {
            NextIndex = Middle + 1;
            Count -= Step + 1;
        }
        else
        {
            Count = Step;
        }
    }

    const int32 PrevIndex = NextIndex - 1;
    const float PrevCurveValue = CurveBuffer.GetValue(PrevIndex);
    const float NextCurveValue = CurveBuffer.GetValue(NextIndex);
    const float PrevCurveTime = CurveBuffer.GetTime(PrevIndex);
    const float NextCurveTime = CurveBuffer.GetTime(NextIndex);

*    // Find time by two nearest known points on the curve*
    const float Diff = NextCurveValue - PrevCurveValue;
    const float Alpha = !FMath::IsNearlyZero(Diff) ? (CurveValue - PrevCurveValue) / Diff : 0.0f;
    return FMath::Lerp(PrevCurveTime, NextCurveTime, Alpha);
}


P.S.: If you know how to improve code or found a bug, please let me know.
P.P.S: same in gist Get time by value from curve compressed with Uniform Indexable · GitHub