开发内容分享_UE4自定义相机碰撞组件

分享自己写的 相机碰撞组件

  • 相比较UE4自带的SpringArm中的碰撞,主要特点在于前后推进速度不一样
  • 在碰撞时 向前推进的速度较快,在离开碰撞时 向后退的速度较慢

对比SpringArm自带的碰撞检测

  • SpringArm的碰撞检测,在墙角的位置,由于频繁的碰撞和离开,导致来回的闪动


  • 我的碰撞检测组件
  • 推进,后退 使用不同的差值速度,避免相机频繁推拉,视觉感受上更舒适


C++ 代码部分

  • h
// TAZORN.COM  2017 ALL RIGHTS RESERVED
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "CameraCollisionComponentBase.generated.h"

/*
    相机碰撞组件,可以被Bp继承,继续修改或复写

*/
UCLASS(Blueprintable, BlueprintType, ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class XLABORATORY_API UCameraCollisionComponentBase : public UActorComponent
{
    GENERATED_BODY()

public:

    UCameraCollisionComponentBase();

    // SpringArm组件的引用
    USpringArmComponent* SpringComponent;

    float DesiredDistance;

    float CamSpringCurrLength;

    float HitLength;

    float CameraLerpSpeed;

    float Delta;

    virtual void BeginPlay() override;

    virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

    UPROPERTY(BlueprintReadWrite, Category = "CameraCollision")
        bool bEnable;

    UPROPERTY(BlueprintReadWrite, Category = "CameraCollision")
        float CameraTraceRadius;

    // 推进的差值速度
    UPROPERTY(BlueprintReadWrite, Category = "CameraCollision")
        float PushSpeed;

    // 拉远的差值速度
    UPROPERTY(BlueprintReadWrite, Category = "CameraCollision")
        float PullSpeed;

    UFUNCTION(BlueprintCallable, Category = "CameraCollision")
        void Init(USpringArmComponent* InSpringComponent);

    UFUNCTION(BlueprintCallable, Category = "CameraCollision")
        void CalcCameraCollision(USpringArmComponent* SpringArm, float InDesiredDistance, float InPushSpeed, float InPullSpeed);

    UFUNCTION(BlueprintCallable, Category = "CameraCollision")
        void SetDesiredDistance(float InDesiredDistance);

    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "CameraCollision")
        float GetDesiredDistance();

    // 需要在Bp中,指定碰撞的通道
    UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (Bitmask, BitmaskEnum = "ECollisionChannel"), Category = "CameraCollision")
        int32 ObjectType;

    // 简化的球面检测
    bool SphereTrace(AActor* ActorToIgnore, const FVector& Start, const FVector& End, const float Radius,
        FHitResult& HitOut, FCollisionObjectQueryParams& TraceChannels);

};


  • cpp
// TAZORN.COM  2017 ALL RIGHTS RESERVED
#include "CameraCollisionComponentBase.h"

// 构造函数
UCameraCollisionComponentBase::UCameraCollisionComponentBase()
{
    PrimaryComponentTick.bCanEverTick = true;

    // 属性默认值
    DesiredDistance = 400.f;
    CameraTraceRadius = 30.f;
    PushSpeed = 12.f;
    PullSpeed = 0.8f;
    bEnable = true;

}

void UCameraCollisionComponentBase::BeginPlay()
{
    Super::BeginPlay();

}

void UCameraCollisionComponentBase::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
    Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
    Delta = DeltaTime;

    if (SpringComponent && bEnable)
    {
        CalcCameraCollision(SpringComponent, DesiredDistance, PushSpeed, PullSpeed);
    }
}

// 初始化,需要在Bp中指定 SpringArm组件引用
void UCameraCollisionComponentBase::Init(USpringArmComponent* InSpringComponent)
{
    SpringComponent = InSpringComponent;
}

// 计算碰撞
void UCameraCollisionComponentBase::CalcCameraCollision(
    USpringArmComponent* SpringArm, float InDesiredDistance, float InPushSpeed, float InPullSpeed)
{
   // 开始结束点,获得SprintArm的位置,以及反向*希望的距离作为结束点
    FVector start = SpringArm->GetComponentToWorld().GetLocation();
    FVector end = (SpringArm->GetForwardVector() * -1.f * DesiredDistance) + start;

    // 碰撞通道
    FCollisionObjectQueryParams Channels(ObjectType);

    // 使用简化的球面检测函数
    FHitResult HitOut = FHitResult(ForceInit);
    bool hit = SphereTrace(SpringArm->GetOwner(), start, end, CameraTraceRadius, HitOut, Channels);
    if (hit)
    {
        HitLength = (HitOut.Location - start).Size();
    }
    else
    {
        HitLength = InDesiredDistance;
    }

    // 差值
    CamSpringCurrLength = FMath::FInterpTo(CamSpringCurrLength, HitLength, Delta, CameraLerpSpeed);
    CameraLerpSpeed = (CamSpringCurrLength - HitLength > 0.f) ? PushSpeed : PullSpeed;

    // 设置到SprintArm
    SpringArm->TargetArmLength = CamSpringCurrLength;

}

// 设置DesiredDistance
void UCameraCollisionComponentBase::SetDesiredDistance(float InDesiredDistance)
{
    DesiredDistance = InDesiredDistance;
}

float UCameraCollisionComponentBase::GetDesiredDistance()
{
    return DesiredDistance;
}

// 简化的球面检测函数
bool UCameraCollisionComponentBase::SphereTrace
(
    AActor* ActorToIgnore,
    const FVector& Start,
    const FVector& End,
    const float Radius,
    FHitResult& HitOut,
    FCollisionObjectQueryParams& TraceChannels
) {
    FCollisionQueryParams TraceParams(true);
    //TraceParams.bTraceComplex = true;
    //TraceParams.bTraceAsyncScene = true;
    TraceParams.bReturnPhysicalMaterial = false;

    //Ignore Actors
    TraceParams.AddIgnoredActor(ActorToIgnore);

    //Re-initialize hit info
    HitOut = FHitResult(ForceInit);

    return GetWorld()->SweepSingleByObjectType
    (
        HitOut,
        Start,
        End,
        FQuat(),
        TraceChannels,
        FCollisionShape::MakeSphere(Radius),
        TraceParams
    );
}


在Bp中使用

  • 编译后在Editor中创建蓝图,继承CameraCollisionComponentBase

  • 我这里给蓝图的命名为 BPC_CameraCollision

  • 在一个设置有SpringArm以及相机的蓝图中使用 BPC_CameraCollision

  • 关闭原有SpringArm的相机碰撞

  • 添加该组件,在BeginPlay调用Init,把 SpringArm引用设置进去

  • 在BPC_CameraComponent属性栏 CameraCollision 中设置 碰撞通道

  • 通过设置DesiredDistance 来进行缩放

发表评论

电子邮件地址不会被公开。 必填项已用*标注