添加镜头的最小距离

This commit is contained in:
997146918 2025-07-25 17:16:46 +08:00
parent 2ec5f3df07
commit f2e125969e
7 changed files with 218 additions and 6 deletions

Binary file not shown.

View File

@ -0,0 +1,179 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "ShipSpringArmComponent.h"
#include "PhysicsEngine/PhysicsSettings.h"
// Sets default values for this component's properties
UShipSpringArmComponent::UShipSpringArmComponent()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
// ...
}
// Called when the game starts
void UShipSpringArmComponent::BeginPlay()
{
Super::BeginPlay();
// ...
}
void UShipSpringArmComponent::UpdateDesiredArmLocation(bool bDoTrace, bool bDoLocationLag, bool bDoRotationLag,
float DeltaTime)
{
FRotator DesiredRot = GetTargetRotation();
// If our viewtarget is simulating using physics, we may need to clamp deltatime
if (bClampToMaxPhysicsDeltaTime)
{
// Use the same max timestep cap as the physics system to avoid camera jitter when the viewtarget simulates less time than the camera
DeltaTime = FMath::Min(DeltaTime, UPhysicsSettings::Get()->MaxPhysicsDeltaTime);
}
// Apply 'lag' to rotation if desired
if(bDoRotationLag)
{
if (bUseCameraLagSubstepping && DeltaTime > CameraLagMaxTimeStep && CameraRotationLagSpeed > 0.f)
{
const FRotator ArmRotStep = (DesiredRot - PreviousDesiredRot).GetNormalized() * (1.f / DeltaTime);
FRotator LerpTarget = PreviousDesiredRot;
float RemainingTime = DeltaTime;
while (RemainingTime > UE_KINDA_SMALL_NUMBER)
{
const float LerpAmount = FMath::Min(CameraLagMaxTimeStep, RemainingTime);
LerpTarget += ArmRotStep * LerpAmount;
RemainingTime -= LerpAmount;
DesiredRot = FRotator(FMath::QInterpTo(FQuat(PreviousDesiredRot), FQuat(LerpTarget), LerpAmount, CameraRotationLagSpeed));
PreviousDesiredRot = DesiredRot;
}
}
else
{
DesiredRot = FRotator(FMath::QInterpTo(FQuat(PreviousDesiredRot), FQuat(DesiredRot), DeltaTime, CameraRotationLagSpeed));
}
}
PreviousDesiredRot = DesiredRot;
// Get the spring arm 'origin', the target we want to look at
FVector ArmOrigin = GetComponentLocation() + TargetOffset;
// We lag the target, not the actual camera position, so rotating the camera around does not have lag
FVector DesiredLoc = ArmOrigin;
if (bDoLocationLag)
{
if (bUseCameraLagSubstepping && DeltaTime > CameraLagMaxTimeStep && CameraLagSpeed > 0.f)
{
const FVector ArmMovementStep = (DesiredLoc - PreviousDesiredLoc) * (1.f / DeltaTime);
FVector LerpTarget = PreviousDesiredLoc;
float RemainingTime = DeltaTime;
while (RemainingTime > UE_KINDA_SMALL_NUMBER)
{
const float LerpAmount = FMath::Min(CameraLagMaxTimeStep, RemainingTime);
LerpTarget += ArmMovementStep * LerpAmount;
RemainingTime -= LerpAmount;
DesiredLoc = FMath::VInterpTo(PreviousDesiredLoc, LerpTarget, LerpAmount, CameraLagSpeed);
PreviousDesiredLoc = DesiredLoc;
}
}
else
{
DesiredLoc = FMath::VInterpTo(PreviousDesiredLoc, DesiredLoc, DeltaTime, CameraLagSpeed);
}
// Clamp distance if requested
bool bClampedDist = false;
if (CameraLagMaxDistance > 0.f)
{
const FVector FromOrigin = DesiredLoc - ArmOrigin;
if (FromOrigin.SizeSquared() > FMath::Square(CameraLagMaxDistance))
{
DesiredLoc = ArmOrigin + FromOrigin.GetClampedToMaxSize(CameraLagMaxDistance);
bClampedDist = true;
}
}
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
if (bDrawDebugLagMarkers)
{
DrawDebugSphere(GetWorld(), ArmOrigin, 5.f, 8, FColor::Green);
DrawDebugSphere(GetWorld(), DesiredLoc, 5.f, 8, FColor::Yellow);
const FVector ToOrigin = ArmOrigin - DesiredLoc;
DrawDebugDirectionalArrow(GetWorld(), DesiredLoc, DesiredLoc + ToOrigin * 0.5f, 7.5f, bClampedDist ? FColor::Red : FColor::Green);
DrawDebugDirectionalArrow(GetWorld(), DesiredLoc + ToOrigin * 0.5f, ArmOrigin, 7.5f, bClampedDist ? FColor::Red : FColor::Green);
}
#endif
}
PreviousArmOrigin = ArmOrigin;
PreviousDesiredLoc = DesiredLoc;
// Now offset camera position back along our rotation
DesiredLoc -= DesiredRot.Vector() * TargetArmLength;
// Add socket offset in local space
DesiredLoc += FRotationMatrix(DesiredRot).TransformVector(SocketOffset);
// Do a sweep to ensure we are not penetrating the world
FVector ResultLoc;
if (bDoTrace && (TargetArmLength != 0.0f))
{
bIsCameraFixed = true;
FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(SpringArm), false, GetOwner());
FHitResult Result;
GetWorld()->SweepSingleByChannel(Result, ArmOrigin, DesiredLoc, FQuat::Identity, ProbeChannel, FCollisionShape::MakeSphere(ProbeSize), QueryParams);
UnfixedCameraPosition = DesiredLoc;
//设置机械臂的最小镜头距离
if (FVector::Dist(ArmOrigin, Result.Location) > MinArmLength)
ResultLoc = BlendLocations(DesiredLoc, Result.Location, Result.bBlockingHit, DeltaTime);
else
{
ResultLoc = DesiredLoc;
}
//FVector::Dist(ArmOrigin, tempResult) > MinArmLength
if (ResultLoc == DesiredLoc )
{
bIsCameraFixed = false;
}
}
else
{
ResultLoc = DesiredLoc;
bIsCameraFixed = false;
UnfixedCameraPosition = ResultLoc;
}
// Form a transform for new world transform for camera
FTransform WorldCamTM(DesiredRot, ResultLoc);
// Convert to relative to component
FTransform RelCamTM = WorldCamTM.GetRelativeTransform(GetComponentTransform());
// Update socket location/rotation
RelativeSocketLocation = RelCamTM.GetLocation();
RelativeSocketRotation = RelCamTM.GetRotation();
UpdateChildTransforms();
}
// Called every frame
void UShipSpringArmComponent::TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// ...
}

View File

@ -0,0 +1,31 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/SpringArmComponent.h"
#include "ShipSpringArmComponent.generated.h"
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class PROJECTFISH_API UShipSpringArmComponent : public USpringArmComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UShipSpringArmComponent();
protected:
// Called when the game starts
virtual void BeginPlay() override;
virtual void UpdateDesiredArmLocation(bool bDoTrace, bool bDoLocationLag, bool bDoRotationLag, float DeltaTime);
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction) override;
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float MinArmLength = 200.f;
};

View File

@ -243,7 +243,7 @@ struct FShipDataConfig
/*** Camera ***/ /*** Camera ***/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Position", meta = (ForceUnits = "cm", ToolTip = "与角色距离")) UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Position", meta = (ForceUnits = "cm", ToolTip = "与角色距离"))
float CameraDistance = 800.0f; float CameraDistance = 1200.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Position", meta = (ForceUnits = "cm", ToolTip = "与角色高度差")) UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Position", meta = (ForceUnits = "cm", ToolTip = "与角色高度差"))
float CameraHeightOffset = 600.0f; float CameraHeightOffset = 600.0f;
@ -266,9 +266,9 @@ struct FShipDataConfig
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Follow", meta = (ToolTip = "镜头跟随阻尼")) UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Follow", meta = (ToolTip = "镜头跟随阻尼"))
float CameraFollowLagRatio = 3.0f; float CameraFollowLagRatio = 3.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Collision", meta = (ToolTip = "镜头跟随阻尼")) // UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Collision", meta = (ToolTip = "镜头跟随阻尼"))
float CameraCollisionLagRatio = 3.0f; // float CameraCollisionLagRatio = 3.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Collision", meta = (ForceUnits = "cm", ToolTip = "与角色的最小距离")) UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Collision", meta = (ForceUnits = "cm", ToolTip = "与角色的最小距离"))
float CameraMinDistance = 200.0f; float CameraMinDistance = 500.0f;
}; };

View File

@ -10,6 +10,7 @@
#include "Components/CapsuleComponent.h" #include "Components/CapsuleComponent.h"
#include "GameFramework/CharacterMovementComponent.h" #include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/SpringArmComponent.h" #include "GameFramework/SpringArmComponent.h"
#include "ProjectFish/Components/ShipSpringArmComponent.h"
class UEnhancedInputLocalPlayerSubsystem; class UEnhancedInputLocalPlayerSubsystem;
@ -41,7 +42,7 @@ AShipbase::AShipbase()
ShipMesh->OnComponentBeginOverlap.AddDynamic(this, &AShipbase::OnOverlapWall); ShipMesh->OnComponentBeginOverlap.AddDynamic(this, &AShipbase::OnOverlapWall);
ShipMesh->SetupAttachment(RootComponent); ShipMesh->SetupAttachment(RootComponent);
//camera arm //camera arm
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom")); CameraBoom = CreateDefaultSubobject<UShipSpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->SetupAttachment(RootComponent); CameraBoom->SetupAttachment(RootComponent);
CameraBoom->TargetArmLength = 400.0f; // The camera follows at this distance behind the character CameraBoom->TargetArmLength = 400.0f; // The camera follows at this distance behind the character
CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller
@ -195,6 +196,7 @@ void AShipbase::ApplyCameraSettings()
{ {
CameraBoom->TargetArmLength = ShipData.CameraDistance; CameraBoom->TargetArmLength = ShipData.CameraDistance;
CameraBoom->SocketOffset = FVector(0, 0, ShipData.CameraHeightOffset); CameraBoom->SocketOffset = FVector(0, 0, ShipData.CameraHeightOffset);
CameraBoom->MinArmLength = ShipData.CameraMinDistance;
FollowCamera->SetRelativeRotation(FRotator(ShipData.CameraGroundAngle, 0, 0)); FollowCamera->SetRelativeRotation(FRotator(ShipData.CameraGroundAngle, 0, 0));
CameraBoom->bEnableCameraLag = true; CameraBoom->bEnableCameraLag = true;

View File

@ -61,7 +61,7 @@ protected:
/***Camera***/ /***Camera***/
UPROPERTY(VisibleAnywhere,BlueprintReadOnly, Category = Camera, meta = ( AllowPrivateAccess = "true")) UPROPERTY(VisibleAnywhere,BlueprintReadOnly, Category = Camera, meta = ( AllowPrivateAccess = "true"))
class USpringArmComponent* CameraBoom; class UShipSpringArmComponent* CameraBoom;
UPROPERTY(VisibleAnywhere,BlueprintReadOnly, Category = Camera, meta = ( AllowPrivateAccess = "true")) UPROPERTY(VisibleAnywhere,BlueprintReadOnly, Category = Camera, meta = ( AllowPrivateAccess = "true"))
class UCameraComponent* FollowCamera; class UCameraComponent* FollowCamera;