一、LerpTransformByCurve函数
可以根据曲线,平滑的对变换进行插值(按引用),相当于使用曲线替换Lerp节点的Alpha值。其返回值表示是否到达插值终点。参数解释:
const FTransform& Start 插值的起点变换
FTransform& Current 当前的变换(按引用),可以被曲线平滑改变
const FTransform& Target 插值的终点变换
const UCurveFloat* Curve 透明度曲线,其取值在0到1之间,以便进行Lerp插值
float& CurveTime 曲线的当前时间
const float& DeltaSeconds 场景时间
static bool LerpTransformByCurve(const FTransform& Start,FTransform& Current,const FTransform& Target,const UCurveFloat* Curve,float& CurveTime,const float& DeltaSeconds)
{
if(Curve)
{
CurveTime = CurveTime + DeltaSeconds;
float MinTime,MaxTime;
Curve->GetTimeRange(MinTime,MaxTime);
CurveTime = FMath::Clamp(CurveTime,MinTime,MaxTime);
FTransform LerpTransform = UKismetMathLibrary::TLerp(Start,Target,Curve->GetFloatValue(CurveTime),ELerpInterpolationMode::DualQuatInterp);
//直接赋值,不考虑过渡
//Current = LerpTransform;
//使用插值赋值较为平滑
Current = UKismetMathLibrary::TInterpTo(Current,LerpTransform,DeltaSeconds,20.0f);
if(CurveTime >= MaxTime)
{
CurveTime = 0.0f;
return true;
}
}
return false;
}
需要在Tick内使用。用法举例:
FTransform Start = 起始值;//假设已经赋值了
FTransform End = 终点值;//假设已经赋值了
float MyCurveTime = 0.0f;//假设从曲线起始时间向后进行插值
void AMyClass::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
//用一个bool控制是否进行插值
if (bLerpMyTransform)
{
//用IsFinished取得返回值,如果为true表示已经插值完毕,如果为false表示还没有插值到终点
bool IsFinished = LerpTransformByCurve(Start,MyTransform,End,MyCurve,MyCurveTime,DeltaSeconds);
//ON TICK
if (IsFinished)
{
//ON FINISHED
//如果插值完毕,就停止插值
bLerpMyTransform = false;
}
//在插值的过程中,MyTransform、MyCurveTime会一直保持更新,随时可以直接使用
}
}
二、LerpFloatByCurve函数
static bool LerpFloatByCurve(const float& Start,float& Current,const float& Target,const UCurveFloat* Curve,float& CurveTime,const float& DeltaSeconds)
{
if(Curve)
{
CurveTime = CurveTime + DeltaSeconds;
float MinTime,MaxTime;
Curve->GetTimeRange(MinTime,MaxTime);
CurveTime = FMath::Clamp(CurveTime,MinTime,MaxTime);
float LerpFloat = UKismetMathLibrary::Lerp(Start,Target,Curve->GetFloatValue(CurveTime));
//直接赋值,不考虑过渡
//Current = LerpFloat;
//使用插值赋值较为平滑
Current = UKismetMathLibrary::FInterpTo(Current,LerpFloat,DeltaSeconds,20.0f);
if(CurveTime >= MaxTime)
{
CurveTime = 0.0f;
return true;
}
}
return false;
}
三、当然,更加优雅的方式
DECLARE_DELEGATE(FOnLerpTick);
DECLARE_DELEGATE(FOnLerpFinished);
DECLARE_DELEGATE(FOnLerpStop);
USTRUCT(BlueprintType)
struct FLerpTransformByCurve
{
GENERATED_BODY()
public:
FOnLerpTick OnTick;
FOnLerpFinished OnFinished;
FOnLerpStop OnStop;
void StartLerp(UWorld* InWorld,FTransform& Target,FTransform const& A,FTransform const& B,UCurveFloat* Curve,float& CurveTime,
float const& TimerRate,bool const& bForceStopExistingTimer=true)
{
if(bForceStopExistingTimer)
{
StopLerp(InWorld);
}
TimerCallBack = FTimerDelegate::CreateRaw(this, &FLerpTransformByCurve::LerpBody,InWorld,&Target,A,B,
Curve,&CurveTime,TimerRate);
InWorld->GetTimerManager().SetTimer(TimerHandle, TimerCallBack, TimerRate, true);
}
void StopLerp(const UWorld* InWorld) const
{
//ON STOP
OnStop.ExecuteIfBound();
InWorld->GetTimerManager().ClearAllTimersForObject(this);
}
private:
FTimerHandle TimerHandle;
FTimerDelegate TimerCallBack;
void LerpBody(UWorld* InWorld,FTransform* Target,FTransform A,FTransform B,UCurveFloat* Curve,float* CurveTime,float DeltaSeconds)
{
const bool IsFinished = this->LerpTransformByCurve(*Target,A,B,Curve,*CurveTime,DeltaSeconds);
//ON TICK
OnTick.ExecuteIfBound();
if( IsFinished )
{
//ON FINISHED
OnFinished.ExecuteIfBound();
StopLerp(InWorld);
}
}
static bool LerpTransformByCurve(FTransform& Target,const FTransform& A,const FTransform& B,const UCurveFloat* Curve,float& CurveTime,const float& DeltaSeconds)
{
if(Curve)
{
CurveTime = CurveTime + DeltaSeconds;
float MinTime,MaxTime;
Curve->GetTimeRange(MinTime,MaxTime);
CurveTime = FMath::Clamp(CurveTime,MinTime,MaxTime);
const FTransform LerpTransform = UKismetMathLibrary::TLerp(A,B,Curve->GetFloatValue(CurveTime),ELerpInterpolationMode::DualQuatInterp);
Target = UKismetMathLibrary::TInterpTo(Target,LerpTransform,DeltaSeconds,20.0f);
if(CurveTime >= MaxTime)
{
CurveTime = 0.0f;
return true;
}
}
return false;
}
};
FLerpTransformByCurve LerpTransformByCurve;
//可以使用LerpTransformByCurve.OnFinished等来Bind其他事件
LerpTransformByCurve.StartLerp(GetWorld(),MyTransform,Start,End,MyCurve,MyCurveTime,G



