diff --git a/ProjectFish/Content/Gameplay/Ship/BP_Ship.uasset b/ProjectFish/Content/Gameplay/Ship/BP_Ship.uasset index d0710bb..c641030 100644 Binary files a/ProjectFish/Content/Gameplay/Ship/BP_Ship.uasset and b/ProjectFish/Content/Gameplay/Ship/BP_Ship.uasset differ diff --git a/ProjectFish/Content/Maps/Ship.umap b/ProjectFish/Content/Maps/Ship.umap index 5164651..a2244d6 100644 Binary files a/ProjectFish/Content/Maps/Ship.umap and b/ProjectFish/Content/Maps/Ship.umap differ diff --git a/ProjectFish/Source/ProjectFish/Components/ShipSpringArmComponent.cpp b/ProjectFish/Source/ProjectFish/Components/ShipSpringArmComponent.cpp new file mode 100644 index 0000000..0064acc --- /dev/null +++ b/ProjectFish/Source/ProjectFish/Components/ShipSpringArmComponent.cpp @@ -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); + + // ... +} + diff --git a/ProjectFish/Source/ProjectFish/Components/ShipSpringArmComponent.h b/ProjectFish/Source/ProjectFish/Components/ShipSpringArmComponent.h new file mode 100644 index 0000000..1dac2a1 --- /dev/null +++ b/ProjectFish/Source/ProjectFish/Components/ShipSpringArmComponent.h @@ -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; +}; diff --git a/ProjectFish/Source/ProjectFish/Definations.h b/ProjectFish/Source/ProjectFish/Definations.h index 5a7875d..f0d9422 100644 --- a/ProjectFish/Source/ProjectFish/Definations.h +++ b/ProjectFish/Source/ProjectFish/Definations.h @@ -243,7 +243,7 @@ struct FShipDataConfig /*** Camera ***/ 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 = "与角色高度差")) float CameraHeightOffset = 600.0f; @@ -266,9 +266,9 @@ struct FShipDataConfig UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Follow", meta = (ToolTip = "镜头跟随阻尼")) float CameraFollowLagRatio = 3.0f; - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Collision", meta = (ToolTip = "镜头跟随阻尼")) - float CameraCollisionLagRatio = 3.0f; + // UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Collision", meta = (ToolTip = "镜头跟随阻尼")) + // float CameraCollisionLagRatio = 3.0f; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera|Collision", meta = (ForceUnits = "cm", ToolTip = "与角色的最小距离")) - float CameraMinDistance = 200.0f; + float CameraMinDistance = 500.0f; }; diff --git a/ProjectFish/Source/ProjectFish/Gameplay/Ship/Shipbase.cpp b/ProjectFish/Source/ProjectFish/Gameplay/Ship/Shipbase.cpp index 49bc45f..8e94dd7 100644 --- a/ProjectFish/Source/ProjectFish/Gameplay/Ship/Shipbase.cpp +++ b/ProjectFish/Source/ProjectFish/Gameplay/Ship/Shipbase.cpp @@ -10,6 +10,7 @@ #include "Components/CapsuleComponent.h" #include "GameFramework/CharacterMovementComponent.h" #include "GameFramework/SpringArmComponent.h" +#include "ProjectFish/Components/ShipSpringArmComponent.h" class UEnhancedInputLocalPlayerSubsystem; @@ -41,7 +42,7 @@ AShipbase::AShipbase() ShipMesh->OnComponentBeginOverlap.AddDynamic(this, &AShipbase::OnOverlapWall); ShipMesh->SetupAttachment(RootComponent); //camera arm - CameraBoom = CreateDefaultSubobject(TEXT("CameraBoom")); + CameraBoom = CreateDefaultSubobject(TEXT("CameraBoom")); CameraBoom->SetupAttachment(RootComponent); CameraBoom->TargetArmLength = 400.0f; // The camera follows at this distance behind the character CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller @@ -195,6 +196,7 @@ void AShipbase::ApplyCameraSettings() { CameraBoom->TargetArmLength = ShipData.CameraDistance; CameraBoom->SocketOffset = FVector(0, 0, ShipData.CameraHeightOffset); + CameraBoom->MinArmLength = ShipData.CameraMinDistance; FollowCamera->SetRelativeRotation(FRotator(ShipData.CameraGroundAngle, 0, 0)); CameraBoom->bEnableCameraLag = true; diff --git a/ProjectFish/Source/ProjectFish/Gameplay/Ship/Shipbase.h b/ProjectFish/Source/ProjectFish/Gameplay/Ship/Shipbase.h index 7ed7209..7cdaf30 100644 --- a/ProjectFish/Source/ProjectFish/Gameplay/Ship/Shipbase.h +++ b/ProjectFish/Source/ProjectFish/Gameplay/Ship/Shipbase.h @@ -61,7 +61,7 @@ protected: /***Camera***/ UPROPERTY(VisibleAnywhere,BlueprintReadOnly, Category = Camera, meta = ( AllowPrivateAccess = "true")) - class USpringArmComponent* CameraBoom; + class UShipSpringArmComponent* CameraBoom; UPROPERTY(VisibleAnywhere,BlueprintReadOnly, Category = Camera, meta = ( AllowPrivateAccess = "true")) class UCameraComponent* FollowCamera;