方法1:使用 Lerp(线性插值) + Timeline(时间轴) 
适合控制移动时长和曲线效果
 
该方法需要三个变量:
StartLocation(Vector):起始位置TargetLocation(Vector):目标位置MoveDuration(Float):移动时长(秒) 
设置时间轴:
添加 Timeline 组件,命名为 MoveTimeline。 
在时间轴中添加 浮点轨道(Float Track) ,命名为 Alpha。 
编辑曲线:0.0 秒时值为 0.0,MoveDuration 秒时值为 1.0(可调整曲线形状控制缓动效果)。 
 
蓝图逻辑:我这里为了测试方便,直接设置了三个变量的值
方法2:使用 VInterp To(向量插值) 
适合每一帧平滑移动,无需设置时间轴,需要配合Event Tick 一起使用
 
需要两个变量:
TargetLocation(Vector):目标位置InterpSpeed(Float):插值速度(推荐 5-10) 
蓝图逻辑:
方法3:使用 MoveComponentTo(组件平滑移动) 
注意使用此方法移动的是相对位置
 
蓝图逻辑:
实现物体匀速到达不同长度的目的地 
实际上本例子是物体按照样条线上的样条点进行移动
 
设置的变量:
MoveSpeed:移动速度StopThreshold:距离目的地多远可以停止TargetLocation:目的地CurrentLocation:当前位置isMoving:是否正在移动ToTarget:剩余方向向量 (TargetLocation - CurrentLocation)VTarget:单位方向向量(Normalize(ToTarget))Distance:距离目的地的距离(VSize(ToTarget)) 
实现步骤:
开始移动时,判断是否已经在目的地:若否,执行下面步骤;若是,不执行
根据当前位置和目的地位置,得到单位方向向量VTarget
计算当前帧需要移动的距离 MoveEachDeltaSeconds:MoveSpeed * DeltaSeconds
如果当前位置和目标位置小于最小步长,则直接移动到目标位置 
否则向目标前进一步CurrentLocation = CurrentLocation + VTarget * MoveEachDeltaSeconds 
 
回到步骤一
 
BoxMove函数
附加:实现物体按照样条线(非样条点)进行移动 蓝图逻辑: 时间轴参照上述方法1设置
触发函数
使用UEC++实现 UEC++实现时间轴
创建一个时间轴组件 
绑定一个浮点曲线(如果需要的话),用于控制时间轴的变化 
绑定时间轴更新和结束的委托 
实现各个函数内的不同需求 
 
创建一个浮点曲线,内部设置同蓝图创建时间轴的浮点曲线设置
MyTimeLine.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 #pragma  once #include  "CoreMinimal.h"  #include  "Components/TimelineComponent.h"  #include  "GameFramework/Actor.h"  #include  "MyTimeLine.generated.h"  DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam (FOnTimelineUpdateDelegate, float , Alpha);UCLASS ()class  ASTAR_TEST2_API  AMyTimeLine : public  AActor{ 	GENERATED_BODY () public :	 	AMyTimeLine (); 	 	virtual  void  Tick (float  DeltaTime)  override  	 	UPROPERTY (VisibleAnywhere,BlueprintReadWrite, Category = "Timeline" ) 	UTimelineComponent* MyTimeline; 	 	UPROPERTY (BlueprintReadWrite,EditAnywhere, Category = "Timeline" ) 	UCurveFloat* FloatCurve; 	 	UPROPERTY (BlueprintAssignable, Category = "Timeline" ) 	FOnTimelineUpdateDelegate FOnTimelineUpdate; 	 	UFUNCTION () 	void  OnTimelineUpdate (float  Value)  	 	UFUNCTION () 	void  OnTimelineFinished ()  	 	UFUNCTION () 	void  OnTimelineEvent ()  	 	 	UFUNCTION (BlueprintCallable, Category = "Timeline" ) 	void  SetPlayRate (float  NewRate)  	 	 	void  PlayTimeline ()  protected :	 	virtual  void  BeginPlay ()  override  private :	 	 	FOnTimelineFloat UpdateFunction; 	FOnTimelineEvent FinishedFunction; }; 
MyTimeLine.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 #include  "MyTimeLine.h"  AMyTimeLine::AMyTimeLine () { 	 	PrimaryActorTick.bCanEverTick = true ; 	 	MyTimeline = CreateDefaultSubobject <UTimelineComponent>(TEXT ("MyTimelineComponent" )); 	 	 	UpdateFunction.BindUFunction (this , FName ("OnTimelineUpdate" )); 	FinishedFunction.BindUFunction (this , FName ("OnTimelineFinished" )); 	 	 	static  ConstructorHelpers::FObjectFinder<UCurveFloat> CurveAsset (TEXT("CurveFloat'/Game/BP/TimeLineCurve.TimeLineCurve'" ))  	if  (CurveAsset.Succeeded ()) FloatCurve = CurveAsset.Object; } void  AMyTimeLine::BeginPlay () 	Super::BeginPlay (); 	 	 	if  (FloatCurve) { 		MyTimeline->AddInterpFloat (FloatCurve, UpdateFunction); 		UE_LOG (LogTemp, Warning, TEXT ("FloatCurve,存在" )); 	} 	 	MyTimeline->SetTimelineFinishedFunc (FinishedFunction);      } void  AMyTimeLine::Tick (float  DeltaTime) 	Super::Tick (DeltaTime); 	 	if  (MyTimeline->IsPlaying ()) { 		MyTimeline->TickComponent (DeltaTime, LEVELTICK_TimeOnly, nullptr ); 	} } void  AMyTimeLine::OnTimelineUpdate (float  Value) 	 	 	FOnTimelineUpdate.Broadcast (Value); 	UE_LOG (LogTemp, Warning, TEXT ("Timeline Value: %f" ), Value); } void  AMyTimeLine::OnTimelineFinished () 	UE_LOG (LogTemp, Warning, TEXT ("Timeline Finished!" )); } void  AMyTimeLine::OnTimelineEvent () 	UE_LOG (LogTemp, Warning, TEXT ("Timeline Event Triggered!" )); } void  AMyTimeLine::SetPlayRate (float  NewRate) 	if  (MyTimeline) 	{ 		MyTimeline->SetPlayRate (NewRate); 	} } void  AMyTimeLine::PlayTimeline () 	if  (MyTimeline) MyTimeline->Play (); } 
剩余部分实现:
BoxMove.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class  ASpine ;class  USplineComponent ;UCLASS ()class  ASTAR_TEST2_API  ABoxMove : public  AActor{ 	GENERATED_BODY () public :	 	ABoxMove (); 	 	virtual  void  Tick (float  DeltaTime)  override  	UFUNCTION () 	void  MoveBySpline ()  	UFUNCTION () 	void  HandleTimelineUpdate (float  Alpha)  	AMyTimeLine* TimelineActor; 	 protected :	 	virtual  void  BeginPlay ()  override  private :	USplineComponent* SplineComp ; 	ASpine* SpineRef = nullptr  ; 	 }; 
BoxMove.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 ABoxMove::ABoxMove () { 	 	PrimaryActorTick.bCanEverTick = true ; } void  ABoxMove::BeginPlay () 	Super::BeginPlay (); } void  ABoxMove::Tick (float  DeltaTime) 	Super::Tick (DeltaTime); } void  ABoxMove::MoveBySpline () 	 	TimelineActor = GetWorld ()->SpawnActor <AMyTimeLine>(); 	if  (!TimelineActor) UE_LOG (LogTemp, Warning, TEXT ("TimelineActor不存在" )); 	if  (TimelineActor) 	{ 		 		TimelineActor ->FOnTimelineUpdate.AddDynamic (this , &ABoxMove::HandleTimelineUpdate); 		 		TimelineActor->SetPlayRate (0.2f ); 		 		TimelineActor->PlayTimeline (); 	} 	for  (TActorIterator<ASpine> It (GetWorld ()); It; ++It) 	{ 		SpineRef = *It; 	} 	SplineComp = SpineRef -> FindComponentByClass <USplineComponent>(); } void  ABoxMove::HandleTimelineUpdate (float  Alpha) 	float  SplineLength = SplineComp->GetSplineLength (); 	double  Lerp = UKismetMathLibrary::Lerp (0.0f , SplineLength, Alpha); 	FVector LocationAtDistanceAlongSpline = SplineComp -> GetLocationAtDistanceAlongSpline (Lerp, ESplineCoordinateSpace::World); 	LocationAtDistanceAlongSpline += FVector (0.0f , 0.0f , 25.0f ); 	SetActorLocation (LocationAtDistanceAlongSpline); }