效果展示
上篇那样做,镜头和人物走着走着就会跑偏,所以这章完成镜头时刻紧跟着角色。 首先要将更新镜头位置的这个函数删除,之后会换成C++的代码。
创建接口
接口的使用我在之前的文章中讲过了, 所以这里就不讲啦。【【UE4 C++】如何使用C++接口】 命名为:ALS_Camera
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ALS_Camera.generated.h"
UINTERFACE(MinimalAPI)
class UALS_Camera : public UInterface
{
GENERATED_BODY()
};
class ALSVLEARNDEMO_API IALS_Camera
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintNativeEvent)
FTransform Get3PPivotTarget();
virtual FTransform Get3PPivotTarget_Implementation();
UFUNCTION(BlueprintNativeEvent)
bool GetCameraParameters(float& TP_FOV, float& FP_FOV);
virtual bool GetCameraParameters_Implementation(float& TP_FOV, float& FP_FOV);
};
源文件这边就默认定义一下就好了。 注释中有说到这个源文件的主要作用就是为任何非纯虚函数添加默认功能。
#include "ALS_Camera.h"
FTransform IALS_Camera::Get3PPivotTarget_Implementation()
{
return {};
}
bool IALS_Camera::GetCameraParameters_Implementation(float& TP_FOV, float& FP_FOV)
{
return false;
}
在角色类中进行接口的实现
在角色的基类中继承接口,并重新实现接口函数。
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Interfaces/ALS_Camera.h"
#include "ALSVLearnDemoCharacter.generated.h"
UCLASS(config=Game)
class AALSVLearnDemoCharacter : public ACharacter, public IALS_Camera
{
GENERATED_BODY()
public:
……
……
……
UPROPERTY(Category="Camera System", EditInstanceOnly, BlueprintReadWrite)
float ThirdPersonFOV;
UPROPERTY(Category="Camera System", EditInstanceOnly, BlueprintReadWrite)
float FirstPersonFOV;
UPROPERTY(Category="Camera System", EditInstanceOnly, BlueprintReadWrite)
bool bRightShoulder;
virtual bool GetCameraParameters_Implementation(float& TP_FOV, float& FP_FOV) override;
};
就是将参数传到接口中。
#include "ALSVLearnDemoCharacter.h"
#include "Components/CapsuleComponent.h"
#include "Components/InputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/Controller.h"
AALSVLearnDemoCharacter::AALSVLearnDemoCharacter()
{
……
……
……
ThirdPersonFOV = 90.f;
FirstPersonFOV = 90.f;
}
……
……
……
bool AALSVLearnDemoCharacter::GetCameraParameters_Implementation(float& TP_FOV, float& FP_FOV)
{
TP_FOV = ThirdPersonFOV;
FP_FOV = FirstPersonFOV;
return bRightShoulder;
}
然后再到ALS_AnimMan_Character 角色中将另一个函数进行重载实现。
#pragma once
#include "CoreMinimal.h"
#include "../ALSVLearnDemoCharacter.h"
#include "ALS_AnimMan_Character.generated.h"
UCLASS()
class ALSVLEARNDEMO_API AALS_AnimMan_Character : public AALSVLearnDemoCharacter
{
GENERATED_BODY()
public:
virtual FTransform Get3PPivotTarget_Implementation() override;
};
源文件:
#include "ALS_AnimMan_Character.h"
FTransform AALS_AnimMan_Character::Get3PPivotTarget_Implementation()
{
const FVector Location = (GetMesh()->GetSocketLocation(TEXT("head")) + GetMesh()->GetSocketLocation(TEXT("root")))
/ 2.f;
return FTransform(GetActorRotation(), Location, FVector(1.f, 1.f, 1.f));
}
添加摄像机移动逻辑
重载UpdateViewTargetInternal 更新摄像机位置。
#pragma once
#include "CoreMinimal.h"
#include "Camera/PlayerCameraManager.h"
#include "ALS_CameraManager.generated.h"
class UALS_PlayerCameraBehavior;
UCLASS()
class ALSVLEARNDEMO_API AALS_CameraManager : public APlayerCameraManager
{
GENERATED_BODY()
public:
AALS_CameraManager();
UFUNCTION(BlueprintCallable)
void OnPossess(APawn* NewPawn);
virtual void UpdateViewTargetInternal(FTViewTarget& OutVT, float DeltaTime) override;
UFUNCTION(BlueprintCallable)
void CustomCameraBehavior(FVector& Location, FRotator& Rotation, float& FOV);
UFUNCTION(BlueprintCallable)
float GetCameraBehaviorParam(FName CurveName);
UFUNCTION(BlueprintCallable)
FVector CalculateAxisIndependentLag(FVector CurrentLocation, FVector TargetLocation, FRotator CameraRotation, FVector LagSpeeds);
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
FRotator TargetCameraRotation;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
FVector TargetCameraLocation;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
FTransform SmoothedPivotTarget;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
FVector PivotLocation;
UFUNCTION(Category="Components", BlueprintCallable)
USkeletalMeshComponent* GetCameraBehaviorComp() const { return CameraBehaviorComp; }
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
APawn* ControllerPawn;
UPROPERTY()
UALS_PlayerCameraBehavior* PlayerCameraBehavior;
private:
UPROPERTY(Category="Components", VisibleAnywhere, BlueprintReadOnly, meta=(AllowPrivateAccess = "true"))
USkeletalMeshComponent* CameraBehaviorComp;
};
源文件:
#include "ALS_CameraManager.h"
#include "ALS_PlayerCameraBehavior.h"
#include "ALSVLearnDemo/Interfaces/ALS_Camera.h"
#include "Kismet/KismetMathLibrary.h"
AALS_CameraManager::AALS_CameraManager()
{
CameraBehaviorComp = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("CameraBehaviorComp"));
CameraBehaviorComp->SetupAttachment(RootComponent);
}
void AALS_CameraManager::UpdateViewTargetInternal(FTViewTarget& OutVT, float DeltaTime)
{
if (!IsValid(OutVT.Target)) return;
if (OutVT.Target->ActorHasTag(TEXT("ALS_Character")))
{
CustomCameraBehavior(OutVT.POV.Location, OutVT.POV.Rotation, OutVT.POV.FOV);
}
else
{
Super::UpdateViewTargetInternal(OutVT, DeltaTime);
}
}
void AALS_CameraManager::OnPossess(APawn* NewPawn)
{
ControllerPawn = NewPawn;
PlayerCameraBehavior = Cast<UALS_PlayerCameraBehavior>(CameraBehaviorComp->GetAnimInstance());
}
void AALS_CameraManager::CustomCameraBehavior(FVector& Location, FRotator& Rotation, float& FOV)
{
IALS_Camera* CameraInterface = Cast<IALS_Camera>(ControllerPawn);
if (!CameraInterface) return;
const FTransform PivotTarget = CameraInterface->Execute_Get3PPivotTarget(ControllerPawn);
float TP_FOV, FP_FOV;
CameraInterface->Execute_GetCameraParameters(ControllerPawn, TP_FOV, FP_FOV);
const FRotator CurrentRotation = GetCameraRotation();
const FRotator TargetRotation = GetOwningPlayerController()->GetControlRotation();
TargetCameraRotation = FMath::RInterpTo(CurrentRotation, TargetRotation, GetWorld()->DeltaTimeSeconds,
GetCameraBehaviorParam(TEXT("RotationLagSpeed")));
const FVector LagLocation = CalculateAxisIndependentLag(SmoothedPivotTarget.GetTranslation(),
PivotTarget.GetTranslation(),
TargetCameraRotation,
FVector(GetCameraBehaviorParam(TEXT("PivotLagSpeed_X")),
GetCameraBehaviorParam(TEXT("PivotLagSpeed_Y")),
GetCameraBehaviorParam(TEXT("PivotLagSpeed_Z"))));
SmoothedPivotTarget = FTransform(PivotTarget.GetRotation(), LagLocation, FVector(1.f, 1.f, 1.f));
FVector ForwardVector = SmoothedPivotTarget.GetRotation().GetForwardVector() * GetCameraBehaviorParam(TEXT("PivotOffset_X"));
FVector RightVector = SmoothedPivotTarget.GetRotation().GetRightVector() * GetCameraBehaviorParam(TEXT("PivotOffset_Y"));
FVector UpVector = SmoothedPivotTarget.GetRotation().GetUpVector() * GetCameraBehaviorParam(TEXT("PivotOffset_Z"));
PivotLocation = SmoothedPivotTarget.GetTranslation() + ForwardVector + RightVector + UpVector;
ForwardVector = TargetCameraRotation.Vector() * GetCameraBehaviorParam(TEXT("CameraOffset_X"));
RightVector = UKismetMathLibrary::GetRightVector(TargetCameraRotation) * GetCameraBehaviorParam(TEXT("CameraOffset_Y"));
UpVector = UKismetMathLibrary::GetUpVector(TargetCameraRotation) * GetCameraBehaviorParam(TEXT("CameraOffset_Z"));
TargetCameraLocation = PivotLocation + ForwardVector + RightVector + UpVector;
Location = TargetCameraLocation;
Rotation = TargetCameraRotation;
FOV = TP_FOV;
}
float AALS_CameraManager::GetCameraBehaviorParam(FName CurveName)
{
if (PlayerCameraBehavior)
{
return PlayerCameraBehavior->GetCurveValue(CurveName);
}
return 0.f;
}
FVector AALS_CameraManager::CalculateAxisIndependentLag(FVector CurrentLocation, FVector TargetLocation,
FRotator CameraRotation, FVector LagSpeeds)
{
const FRotator CameraRotationYaw(0.f, CameraRotation.Yaw, 0.f);
const FVector CurrentLocation_UnRotateVector = CameraRotationYaw.UnrotateVector(CurrentLocation);
const FVector TargetLocation_UnRotateVector = CameraRotationYaw.UnrotateVector(TargetLocation);
FVector Location;
Location.X = FMath::FInterpTo(CurrentLocation_UnRotateVector.X, TargetLocation_UnRotateVector.X,
GetWorld()->DeltaTimeSeconds, LagSpeeds.X);
Location.Y = FMath::FInterpTo(CurrentLocation_UnRotateVector.Y, TargetLocation_UnRotateVector.Y,
GetWorld()->DeltaTimeSeconds, LagSpeeds.Y);
Location.Z = FMath::FInterpTo(CurrentLocation_UnRotateVector.Z, TargetLocation_UnRotateVector.Z,
GetWorld()->DeltaTimeSeconds, LagSpeeds.Z);
return CameraRotationYaw.RotateVector(Location);
}
函数设计思路讲解: 在函数里面为什么要加UnrotatorVector 和 RotatorVector,想了好久都不知道为什么,如果有大佬知道这个希望您能够在评论区评论一下。
编译运行之后将摄像机骨骼加载进去。
创建动画蓝图
先创建一个UAnimInstance 的C++类:ALS_PlayerCameraBehavior 。 先放在一边,之后会用到。
右键
修改参数,运行就完成啦!
|