自定义Movement组件
目的:实现自定义轨迹如抛物线,线性,定点等运动方式,作为组件控制绑定对象的运动。
基类:UMovementComponent
过程:
1.创建UCustomMovementComponenet继承UMovementComponent类,作为各种具体轨迹的父类,完成主要流程的实现。并提供接口给子类override实现具体计算过程。
2.实现子类轨迹计算过程。这里仅提供线性移动轨迹作为示例。
一、UCustomMovementComponent类
/**
* class : UCustomMovementComponent
* author : Jia Zhipeng
* Base class of custom movement component
*/
UCLASS(ClassGroup = Movement, abstract, ShowCategories = (CustomMovement))
class CLIENT_API UCustomMovementComponent : public UMovementComponent
{
GENERATED_UCLASS_BODY()
public:
/*Initialize target position, must be called before TickComponent.
**@param bFixedPoint : whether target position is fixed point or target component
*/
UFUNCTION(BlueprintCallable, Category = CustomMovement)
virtual void SetTargetPosition(bool bFixedPoint, FVector PointLocation, USceneComponent* MoveTarget=nullptr);
//Initialize params which will be used during computation, implementation in derived class.
virtual void InitComputeParams() {};
//Computation process, must be override in derived class.
virtual void ComputeMovement(float DeltaTime, FVector& OutMoveDelta, FQuat& OutNewRotation) {};
//Update process.
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
//Check whether should be stopped
void CheckIsStop();
protected:
FVector GetTargetPosition();
FVector GetHostPosition();
//if bFixedPoint is true, use this location to update.
FVector PointLocation;
//The current target we are homing towards. Can only be set at runtime (when projectile is spawned or updating).
TWeakObjectPtr MoveTarget;
//If true, use fixed point to update location; else, use MoveTarget.
uint32 bFixedPoint:1;
//If true, stop TickComponent
uint32 bStop:1;
};
UCustomMovementComponent::UCustomMovementComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
bStop = false;
}
void UCustomMovementComponent::SetTargetPosition(bool bFixedPoint, FVector PointLocation, USceneComponent* MoveTarget)
{
bStop = false;
this->MoveTarget = MoveTarget;
this->bFixedPoint = bFixedPoint;
this->PointLocation = PointLocation;
InitComputeParams();
}
void UCustomMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
{
//Tick parent method first, in order to know whether UpdatedComponent is null.
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
CheckIsStop();
if (bStop)
return;
FVector OutMoveDelta;
FQuat OutNewRotation;
//计算Location和Rotation的变化
ComputeMovement(DeltaTime, OutMoveDelta, OutNewRotation);
//更改UpdatedComponent坐标值的调用方法
MoveUpdatedComponent(OutMoveDelta, OutNewRotation, true); //whether change orientation?
//UMovementComponent中注释说在更改Velocity变量后需要调用该方法改变UpdatedComponent的Velocity。看源代码后发现应该是其他如物理Body等需要使用该值。
UpdateComponentVelocity();
}
void UCustomMovementComponent::CheckIsStop()
{
if (!UpdatedComponent)
{
bStop = true;
return;
}
//whether target is exist
if (!bFixedPoint && MoveTarget == nullptr)
{
bStop = true;
return;
}
//reach the target location then stop
float LocationDifference = (GetTargetPosition() - UpdatedComponent->GetComponentLocation()).Size();
if (LocationDifference < SMALL_NUMBER)
{
bStop = true;
return;
}
}
FVector UCustomMovementComponent::GetTargetPosition()
{
if (bFixedPoint)
return PointLocation;
check(MoveTarget != nullptr);
return MoveTarget->GetComponentLocation();
}
FVector UCustomMovementComponent::GetHostPosition()
{
check(UpdatedComponent);
return UpdatedComponent->GetComponentLocation();
}
二、ULinearMovementComponent类
/**
* class : ULinearMovementComponent
* author : Jia Zhipeng
* Move from current position to target in a constant velocity.
*/
UCLASS(ClassGroup = Movement, meta = (BlueprintSpawnableComponent), ShowCategories = (CustomMovement))
class CLIENT_API ULinearMovementComponent : public UCustomMovementComponent
{
GENERATED_UCLASS_BODY()
public:
//Linear speed.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = CustomMovement)
float Speed;
virtual void ComputeMovement(float DeltaTime, FVector& OutMoveDelta, FQuat& OutNewRotation) override;
};
ULinearMovementComponent::ULinearMovementComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
Speed = 0;
}
void ULinearMovementComponent::ComputeMovement(float DeltaTime, FVector& OutMoveDelta, FQuat& OutNewRotation)
{
FVector OldVelocity = Velocity;
check(UpdatedComponent);
Velocity = (GetTargetPosition() - UpdatedComponent->GetComponentLocation()).GetSafeNormal() * Speed;
OutMoveDelta = Velocity * DeltaTime;
OutNewRotation = OldVelocity.ToOrientationQuat();//use OldVelocity.Rotation().Quarternion() before 4.11 release.
}
三、使用
1.在蓝图中添加新创建的LinearMovementComponent组件,并设置组件的初始参数如速度。
2.在使用该蓝图创建Actor时,设置MovementComponent的Target,SpawnActor时Initial Velocity没有用。
4.效果