|

?
一、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; } 三、当然,更加优雅的方式 /** ?* 根据曲线对变换进行平滑插值,这相当于于使用浮点曲线控制Lerp的Alpha值 ?* 注册委托是被允许的,可以使用委托在插值的不同阶段添加行为 ?* 但请注意,句柄被CleanTimer销毁后仍然会继续运作,需要使用ClearAllTimersForObject才能销毁。 ?*/ 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
|