智慧 + 毅力 = 无所不能

正确性、健壮性、可靠性、效率、易用性、可读性、可复用性、兼容性、可移植性...

导航

[UE4]自定义MovementComponent组件

Posted on 2018-02-12 11:29  Bill Yuan  阅读(1575)  评论(0编辑  收藏  举报

转自:http://www.cnblogs.com/corgi/p/5405451.html

自定义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<USceneComponent> 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.效果