相比较UE4自带的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;
}
// 设置DesiredDistancevoid 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
);
}
编译后在Editor中创建蓝图,继承CameraCollisionComponentBase
我这里给蓝图的命名为 BPC_CameraCollision
在一个设置有SpringArm以及相机的蓝图中使用 BPC_CameraCollision
关闭原有SpringArm的相机碰撞
添加该组件,在BeginPlay调用Init,把 SpringArm引用设置进去
在BPC_CameraComponent属性栏 CameraCollision 中设置 碰撞通道
通过设置DesiredDistance 来进行设置 默认的相机距离
作者:TAZORN
著作权归作者所有
【相关阅读】:
Maxscript_基础_回调函数:http://tk.v5cg.com/help/246.html
Maxscript_基础_材质处理:http://tk.v5cg.com/help/247.html
Maxscript_基础_修改器操作:http://tk.v5cg.com/help/248.html
Maxscript_基础_创建窗口:http://tk.v5cg.com/help/249.html
Maxscript_基础_遍历与递归:http://tk.v5cg.com/help/250.html
Maxscript_与DotNet交互:http://tk.v5cg.com/help/251.html
【上传发布插件】:
编写3DMAX插件到发布上线全流程:http://tk.v5cg.com/help/147.html
代码上传与工具发布:http://tk.v5cg.com/help/99.html
代码发布,部署实例参考:http://tk.v5cg.com/help/140.html
PS【动作库】代码部署指南:http://tk.v5cg.com/help/141.html
CG云盘 - 开发者使用说明:http://tk.v5cg.com/help/34.html