diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index c1d5b98..09ddd8d 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -63,3 +63,14 @@ ServerDefaultMap=/Engine/Maps/Entry.Entry GlobalDefaultGameMode=/Game/Blueprints/Game/BP_ExoGameMode.BP_ExoGameMode_C GlobalDefaultServerGameMode=None + +[CoreRedirects] ++FunctionRedirects=(OldName="/Script/Exo.ExoPlayerController.UpdateCoverStandHeight",NewName="/Script/Exo.ExoPlayerController.UpdateSmoothCoverCamera") ++FunctionRedirects=(OldName="/Script/Exo.ExoPlayerController.AdjustCameraWhileInCover",NewName="/Script/Exo.ExoPlayerController.CalculateCoverAim") ++FunctionRedirects=(OldName="/Script/Exo.ExoPlayerController.SetNewCameraLocationOffset",NewName="/Script/Exo.ExoPlayerController.SetEyePositionOffset") ++FunctionRedirects=(OldName="/Script/Exo.ExoPlayerController.SetNewCameraRotationOffset",NewName="/Script/Exo.ExoPlayerController.SetEyeRoll") ++PropertyRedirects=(OldName="/Script/Exo.ExoPlayerCharacter.IsInCover",NewName="/Script/Exo.ExoPlayerCharacter.bIsInCover") ++PropertyRedirects=(OldName="/Script/Exo.ExoPlayerCharacter.CoverEyeHeight",NewName="/Script/Exo.ExoPlayerCharacter.LowEyeHeight") ++FunctionRedirects=(OldName="/Script/Exo.ExoPlayerController.CalculateCoverAim",NewName="/Script/Exo.ExoPlayerController.CalculateCoverAimOffset") ++PropertyRedirects=(OldName="/Script/Exo.ExoPlayerController.UseEyeHeight",NewName="/Script/Exo.ExoPlayerController.bUseEyeHeight") ++FunctionRedirects=(OldName="/Script/Exo.ExoPlayerCharacter.SetEyePositionOffset",NewName="/Script/Exo.ExoPlayerCharacter.SetEyePositionOffsetTarget") \ No newline at end of file diff --git a/Content/Blueprints/Characters/Player/BP_ExoPlayerCharacter.uasset b/Content/Blueprints/Characters/Player/BP_ExoPlayerCharacter.uasset index 5ee5a32..f295766 100644 Binary files a/Content/Blueprints/Characters/Player/BP_ExoPlayerCharacter.uasset and b/Content/Blueprints/Characters/Player/BP_ExoPlayerCharacter.uasset differ diff --git a/Content/Blueprints/HeightChecker.uasset b/Content/Blueprints/HeightChecker.uasset new file mode 100644 index 0000000..b70f478 Binary files /dev/null and b/Content/Blueprints/HeightChecker.uasset differ diff --git a/Content/Blueprints/Player/BP_ExoPlayerController.uasset b/Content/Blueprints/Player/BP_ExoPlayerController.uasset index 4ba7094..11b0fb5 100644 Binary files a/Content/Blueprints/Player/BP_ExoPlayerController.uasset and b/Content/Blueprints/Player/BP_ExoPlayerController.uasset differ diff --git a/Content/Levels/TestMap.umap b/Content/Levels/TestMap.umap index 04c8b38..8f81ca9 100644 Binary files a/Content/Levels/TestMap.umap and b/Content/Levels/TestMap.umap differ diff --git a/Source/Exo/Private/Characters/Components/ShootingComponent.cpp b/Source/Exo/Private/Characters/Components/ShootingComponent.cpp index fae5ab7..0ebdcf5 100644 --- a/Source/Exo/Private/Characters/Components/ShootingComponent.cpp +++ b/Source/Exo/Private/Characters/Components/ShootingComponent.cpp @@ -265,6 +265,7 @@ void UShootingComponent::StartAiming() PlayerCharacter->GetCharacterMovement()->MaxWalkSpeed = PlayerCharacter->WalkSpeed * AimingMoveSpeedScale; TargetFOV = CurrentGunBase->AimingFOV; + OnStartedADS.Broadcast(); } } @@ -274,6 +275,8 @@ void UShootingComponent::StopAiming() PlayerCharacter->GetCharacterMovement()->MaxWalkSpeed = PlayerCharacter->WalkSpeed; TargetFOV = DefaultFOV; + + OnStoppedADS.Broadcast(); } void UShootingComponent::Throw() diff --git a/Source/Exo/Private/Characters/ExoPlayerCharacter.cpp b/Source/Exo/Private/Characters/ExoPlayerCharacter.cpp index bb7019b..1b0e232 100644 --- a/Source/Exo/Private/Characters/ExoPlayerCharacter.cpp +++ b/Source/Exo/Private/Characters/ExoPlayerCharacter.cpp @@ -5,6 +5,7 @@ #include "Blueprint/UserWidget.h" #include "Characters/Components/ShootingComponent.h" +#include "Components/CapsuleComponent.h" #include "GameFramework/CharacterMovementComponent.h" #include "Items/AmmoBoxBase.h" #include "Items/HealthBoxBase.h" @@ -15,6 +16,24 @@ AExoPlayerCharacter::AExoPlayerCharacter() { + PrimaryActorTick.bCanEverTick = true; + + // Setup eye height values + StandingEyeHeight = 175.f; + CrouchedEyeHeight = 50.f; + LowEyeHeightOffset = -20.f; + + + CapsuleBottom = CreateDefaultSubobject(TEXT("CapsuleBottom")); + CapsuleBottom->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform); + CapsuleBottom->SetRelativeLocation(FVector(0, 0, -GetCapsuleComponent()->GetScaledCapsuleHalfHeight())); + + // Create camera component + CameraComponent = CreateDefaultSubobject(TEXT("CameraComponent")); + CameraComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform); + CameraComponent->bUsePawnControlRotation = true; + + GetCharacterMovement()->bSnapToPlaneAtStart = true; InteractionComponent = CreateDefaultSubobject(TEXT("Interaction Component")); @@ -30,21 +49,18 @@ AExoPlayerCharacter::AExoPlayerCharacter() //bUseControllerRotationPitch = false; //bUseControllerRotationYaw = true; //bUseControllerRotationRoll = false; - - // Setup camera component - CameraComponent = CreateDefaultSubobject(TEXT("CameraComponent")); - CameraComponent->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform); - CameraComponent->bUsePawnControlRotation = true; - CameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, BaseEyeHeight)); } void AExoPlayerCharacter::BeginPlay() { Super::BeginPlay(); + // Set correct starting camera height + SetTargetEyeHeight(StandingEyeHeight); + CameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, FromFeet(TargetEyeHeight))); + GetCapsuleComponent()->OnComponentBeginOverlap.AddDynamic(this, &AExoPlayerCharacter::OnActorBeginOverlap); //UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0)->SetViewTarget(this); - StandingEyeHeight = CameraComponent->GetRelativeLocation().Z; PlayerHud = CreateWidget(GetWorld(),PlayerHudClass); @@ -64,8 +80,80 @@ void AExoPlayerCharacter::BeginPlay() } } +void AExoPlayerCharacter::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); + + //// NOT FINAL SOLUTION /// + /** Reset camera offset at the start of every frame */ + //TargetEyeLocationOffset = FVector::ZeroVector; + //TargetEyeRoll = 0.f; + ////////////////////////// + + UpdateCameraHeight(DeltaTime); + //ApplyCameraOffset(DeltaTime); +} + +float AExoPlayerCharacter::GetFootOffset() +{ + return -GetCapsuleComponent()->GetScaledCapsuleHalfHeight(); +} + +void AExoPlayerCharacter::UpdateCameraHeight(float DeltaTime) +{ + if (FMath::IsNearlyEqual(GetCurrentEyeHeight(), TargetEyeHeight, 0.01f)) + { + return; + } + + const float NewHeight = FMath::Lerp(GetCurrentEyeHeight(), TargetEyeHeight, DeltaTime*5); + const FVector CamRelXY = CameraComponent->GetRelativeLocation(); + CameraComponent->SetRelativeLocation(FVector(CamRelXY.X, CamRelXY.Y, + GetFootOffset() + NewHeight)); +} + +void AExoPlayerCharacter::ApplyCameraOffset(float DeltaTime) +{ + bool HasChanged = false; + //FVector NewOffset = EyeLocationOffset; + //FVector NoOffsetCameraPosition = CameraComponent->GetRelativeLocation() - EyeLocationOffset; + + if (!FVector::PointsAreNear(EyeLocationOffset, TargetEyeLocationOffset, 0.01f)) + { + // Smoothly offset view + EyeLocationOffset = FMath::Lerp(EyeLocationOffset, TargetEyeLocationOffset, 5*DeltaTime); + HasChanged = true; + } + + if (!FMath::IsNearlyEqual(EyeRoll, TargetEyeRoll, 0.01f)) + { + // Smoothly rotate view + EyeRoll = FMath::Lerp(EyeRoll, TargetEyeRoll, DeltaTime); + HasChanged = true; + } + + if (!HasChanged) + { + // Do not calculate anything if nothing changed + return; + } + + // Update actual camera position + //FVector BaseLocation = FVector(0, 0, GetCurrentEyeHeightBase(true)); + //CameraComponent->SetRelativeLocation(NoOffsetCameraPosition + NewOffset); + //FVector CapsuleRelativeOffset = BaseLocation + EyeLocationOffset; + //CapsuleRelativeOffset.Z += GetCurrentEyeHeightBase(true); + CameraComponent->SetRelativeLocation(EyeLocationOffset); + + UE_LOG(LogTemp, Log, TEXT("Camera relative: %s"), *CameraComponent->GetRelativeLocation().ToString()); + // Update actual camera rotation (Roll) + FRotator NewRotator = GetController()->GetControlRotation(); + NewRotator.Roll = EyeRoll; + GetController()->SetControlRotation(NewRotator); +} + void AExoPlayerCharacter::OnActorBeginOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, - int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) + int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) { if (OtherActor && OtherActor != this) { @@ -96,6 +184,30 @@ void AExoPlayerCharacter::OnActorBeginOverlap(UPrimitiveComponent* OverlappedCom } } +void AExoPlayerCharacter::CrouchCustom() +{ + SetTargetEyeHeight(CrouchedEyeHeight); + GetCharacterMovement()->MaxWalkSpeed = CrouchSpeed; + + float CurrentCamHeight = GetCurrentEyeHeight(); + GetCapsuleComponent()->SetCapsuleHalfHeight(44.f); + CameraComponent->SetRelativeLocation( + FVector(0, 0, GetFootOffset()) + + FVector(0, 0, CurrentCamHeight)); +} + +void AExoPlayerCharacter::UnCrouchCustom() +{ + SetTargetEyeHeight(StandingEyeHeight); + GetCharacterMovement()->MaxWalkSpeed = WalkSpeed; + + float CurrentCamHeight = GetCurrentEyeHeight(); + GetCapsuleComponent()->SetCapsuleHalfHeight(88.f); + CameraComponent->SetRelativeLocation( + FVector(0, 0, GetFootOffset()) + + FVector(0, 0, CurrentCamHeight)); +} + void AExoPlayerCharacter::AddHealthPoints(float addValue) { CurrentHealth += addValue; @@ -105,4 +217,79 @@ void AExoPlayerCharacter::AddHealthPoints(float addValue) if (PlayerHud) PlayerHud->SetHp(CurrentHealth,MaxHealth); -} \ No newline at end of file +} + +float AExoPlayerCharacter::ToFeet(float value) +{ + return value + GetCapsuleComponent()->GetScaledCapsuleHalfHeight(); +} + +float AExoPlayerCharacter::FromFeet(float value) +{ + return value - GetCapsuleComponent()->GetScaledCapsuleHalfHeight(); +} + +/*float AExoPlayerCharacter::GetCurrentEyeHeightBase(const bool bCapsuleRelative) +{ + if (bIsCrouched) + { + return GetCrouchingEyeHeight(bCapsuleRelative); + } + + return GetStandingEyeHeight(bCapsuleRelative); +}*/ + +float AExoPlayerCharacter::GetStandingEyeHeight(const bool bCapsuleRelative) const +{ + return bCapsuleRelative ? StandingEyeHeight - GetCapsuleComponent()->GetScaledCapsuleHalfHeight() + : StandingEyeHeight; +} + +float AExoPlayerCharacter::GetCrouchingEyeHeight(const bool bCapsuleRelative) const +{ + return bCapsuleRelative ? CrouchedEyeHeight - GetCapsuleComponent()->GetScaledCapsuleHalfHeight() + : CrouchedEyeHeight; +} + + +void AExoPlayerCharacter::SetEyePositionOffsetTarget(const FVector LocationOffset) +{ + //LocationOffset.Z = FMath::Clamp(LocationOffset.Z, CoverEyeHeight, StandingEyeHeight); + UE_LOG(LogTemp, Log, TEXT("Eye offset set to: %s"), *LocationOffset.ToString()); + TargetEyeLocationOffset = LocationOffset; +} + +void AExoPlayerCharacter::SetEyeRoll(float RollValue) +{ + TargetEyeRoll = RollValue; +} + +FVector AExoPlayerCharacter::GetPlayerLocationAtFeet() const +{ + FVector ReturnVector = GetActorLocation(); + ReturnVector.Z -= GetCapsuleComponent()->GetScaledCapsuleHalfHeight(); + return ReturnVector; +} + +void AExoPlayerCharacter::SetTargetEyeHeight(float NewEyeHeight, const bool bCapsuleRelative) +{ + if (bCapsuleRelative) + { + NewEyeHeight += GetCapsuleComponent()->GetScaledCapsuleHalfHeight(); + } + UE_LOG(LogTemp, Log, TEXT("Target eye height set to: %f"), NewEyeHeight); + TargetEyeHeight = FMath::Clamp(NewEyeHeight, + CrouchedEyeHeight + LowEyeHeightOffset, StandingEyeHeight + ); +} + +float AExoPlayerCharacter::GetCurrentEyeHeight(const bool bCapsuleRelative) +{ + float ReturnValue = CameraComponent->GetRelativeLocation().Z; + if (!bCapsuleRelative) + { + ReturnValue += GetCapsuleComponent()->GetScaledCapsuleHalfHeight(); + } + + return ReturnValue; +} diff --git a/Source/Exo/Private/Player/ExoPlayerController.cpp b/Source/Exo/Private/Player/ExoPlayerController.cpp index a9b24a0..5a8c7cd 100644 --- a/Source/Exo/Private/Player/ExoPlayerController.cpp +++ b/Source/Exo/Private/Player/ExoPlayerController.cpp @@ -5,9 +5,9 @@ #include "EnhancedInputComponent.h" #include "EnhancedInputSubsystems.h" #include "Characters/ExoPlayerCharacter.h" +#include "Components/CapsuleComponent.h" #include "GameFramework/Character.h" #include "GameFramework/CharacterMovementComponent.h" -#include "Kismet/GameplayStatics.h" AExoPlayerController::AExoPlayerController() { @@ -28,34 +28,43 @@ void AExoPlayerController::BeginPlay() { Subsystem->AddMappingContext(InputContext, 0); } - - //InteractionComponent = PlayerCharacter->FindComponentByClass(); - //ShootingComponent = PlayerCharacter->FindComponentByClass(); + InteractionComponent = PlayerCharacter->InteractionComponent; ShootingComponent = PlayerCharacter->ShootingComponent; // Ustawianie w komponencie poruszania pr�dko�ci zapisanej w characterze PlayerCharacter->GetCharacterMovement()->MaxWalkSpeed = PlayerCharacter->WalkSpeed; - - // Oblicz prawidłową maksymalną wysokość na którą można wychylić się z nad osłony - - UE_LOG(LogTemp, Display, TEXT("MaxCoverAimHeight: %f"), MaxCoverAimHeight); } void AExoPlayerController::PlayerTick(float DeltaTime) { Super::PlayerTick(DeltaTime); - // TESTING - if (bIsInCover) - { - AdjustCameraWhileInCover(); - } - UpdateCoverStandHeight(DeltaTime); + if (PlayerCharacter->bIsInCover) + { + //PlayerCharacter->SetEyePositionOffsetTarget( + // FVector(0, 0, PlayerCharacter->LowEyeHeightOffset) + // ); + if (PlayerCharacter->bIsAimingMode) + { + CoverAimHeightOffset = CalculateCoverAimOffset(); + PlayerCharacter->SetEyePositionOffsetTarget( + FVector(0.f, 0.f, CoverAimHeightOffset)); + } + } + //else + //{ + // PlayerCharacter->SetEyePositionOffsetTarget(FVector::ZeroVector); + //} + + // On screen cover state DEBUG if (bShowCoverSystemDebug) { - GEngine->AddOnScreenDebugMessage(2, -1, FColor::Red, FString::Printf(TEXT("In cover: %s"), bIsInCover ? "true" : "false")); + GEngine->AddOnScreenDebugMessage(2, -1, FColor::Red, + FString::Printf(TEXT("In cover: %hs"), + PlayerCharacter->bIsInCover ? "true" : "false") + ); } } @@ -155,18 +164,21 @@ void AExoPlayerController::PlayerStartCrouch() if (bIsSprinting) { PlayerCharacter->GetCharacterMovement()->MaxWalkSpeedCrouched = PlayerCharacter->SlideSpeed; + PlayerCharacter->SetTargetEyeHeight(PlayerCharacter->LowEyeHeightOffset); GetWorldTimerManager().SetTimer(SlideCooldownTimer, this, &AExoPlayerController::ResetSlide, PlayerCharacter->SlideCooldown, false); } - PlayerCharacter->Crouch(); - PlayerCharacter->CameraComponent->SetRelativeLocation(FVector( - 0.0f, - 0.0f, - PlayerCharacter->CrouchedEyeHeight) - ); + //PlayerCharacter->Crouch(); + PlayerCharacter->CrouchCustom(); + //PlayerCharacter->SetTargetEyeHeight(PlayerCharacter->CrouchedEyeHeight); + // PlayerCharacter->CameraComponent->SetRelativeLocation(FVector( + // 0.0f, + // 0.0f, + // PlayerCharacter->CrouchedEyeHeight) + // ); // Start checking for cover - bIsInCover = CheckForCover(); + PlayerCharacter->bIsInCover = CheckForCover(); GetWorld()->GetTimerManager().SetTimer( CoverCheckTimer, this, @@ -178,22 +190,25 @@ void AExoPlayerController::PlayerStartCrouch() void AExoPlayerController::PlayerStopCrouch() { - PlayerCharacter->UnCrouch(); - PlayerCharacter->CameraComponent->SetRelativeLocation(FVector( - 0.0f, - 0.0f, - PlayerCharacter->BaseEyeHeight) - ); + //PlayerCharacter->UnCrouch(); + PlayerCharacter->UnCrouchCustom(); + //PlayerCharacter->SetTargetEyeHeight(PlayerCharacter->GetStandingEyeHeight()); + // PlayerCharacter->CameraComponent->SetRelativeLocation(FVector( + // 0.0f, + // 0.0f, + // PlayerCharacter->BaseEyeHeight) + // ); // Stop checking for cover GetWorld()->GetTimerManager().ClearTimer(CoverCheckTimer); - bIsInCover = false; + PlayerCharacter->bIsInCover = false; TargetCoverStandAlpha = 0.0f; } void AExoPlayerController::ResetSlide() { PlayerCharacter->GetCharacterMovement()->MaxWalkSpeedCrouched = PlayerCharacter->CrouchSpeed; + PlayerCharacter->SetTargetEyeHeight(PlayerCharacter->CrouchedEyeHeight); } void AExoPlayerController::PlayerStartSprint() @@ -236,6 +251,10 @@ void AExoPlayerController::PlayerStartAim() void AExoPlayerController::PlayerStopAim() { ShootingComponent->StopAiming(); + if (PlayerCharacter->bIsInCover) + { + CalculateCoverAimOffset(); + } } void AExoPlayerController::PlayerMeleAttack() @@ -276,7 +295,10 @@ bool AExoPlayerController::CheckForCover() // Do a simple 8-directional line trace FVector TraceDirection = PlayerCharacter->GetActorForwardVector(); FVector TraceStart = PlayerCharacter->GetActorLocation(); - TraceStart.Z -= PlayerCharacter->GetCapsuleComponent()->GetScaledCapsuleHalfHeight() - CoverObstacleMinHeight; + TraceStart.Z += bUseEyeHeight ? + PlayerCharacter->GetCrouchingEyeHeight(true) + : + PlayerCharacter->GetPlayerLocationAtFeet().Z + CoverObstacleMinHeight; FCollisionQueryParams QueryParams; QueryParams.AddIgnoredActor(PlayerCharacter); @@ -306,11 +328,9 @@ bool AExoPlayerController::CheckForCover() // Check if this particular hit isn't against a wall (>CoverMaxHeight) FHitResult SphereHit; - FVector SpherePosition = Hit.ImpactPoint + - FVector( - 0.0f, 0.0f, - CoverObstacleMaxHeight + CoverAimWindowRadius - CoverObstacleMinHeight); - + FVector SpherePosition = Hit.ImpactPoint; + SpherePosition.Z = PlayerCharacter->GetPlayerLocationAtFeet().Z + CoverObstacleMaxHeight + CoverAimWindowRadius; + GetWorld()->SweepSingleByChannel( SphereHit, SpherePosition, @@ -342,20 +362,27 @@ bool AExoPlayerController::CheckForCover() return ValidHits.Num() > 0; } -void AExoPlayerController::AdjustCameraWhileInCover() +float AExoPlayerController::CalculateCoverAimOffset() { - if (!bIsInCover) + // Nic nie rób jak nie znajdujesz się za osłoną + if (!PlayerCharacter->bIsInCover) { - return; + return 0.f; } - MaxCoverAimHeight = PlayerCharacter->StandingEyeHeight * CoverAimStandFactor; + // Oblicz maksymalną wysokość na którą można wychylić się z nad osłony + MaxCoverAimHeightOffset = PlayerCharacter->GetStandingEyeHeight() * CoverAimStandFactor; - //FVector StartOffset = GetCharacter()->GetActorForwardVector() * 20.0f; FVector ObstacleTraceStart = GetCharacter()->GetActorLocation(); - ObstacleTraceStart.Z += GetCharacter()->CrouchedEyeHeight; + ObstacleTraceStart.Z += + bUseEyeHeight ? + PlayerCharacter->GetCurrentEyeHeight(true) + : + PlayerCharacter->CrouchedEyeHeight - GetCharacter()->GetCapsuleComponent()->GetScaledCapsuleHalfHeight(); + FVector ObstacleTraceEnd = ObstacleTraceStart + PlayerCameraManager->GetCameraRotation().Vector() * CoverAimFreeDistance; + FCollisionQueryParams QueryParams; QueryParams.AddIgnoredActor(PlayerCharacter); TEnumAsByte ObstacleTraceChannel = ECC_WorldStatic; @@ -363,138 +390,97 @@ void AExoPlayerController::AdjustCameraWhileInCover() FHitResult Hit; bool bFreeSpace = false; - // Trace until no hit is found (free space to aim) - for (int i = 0; i < MaxCoverAimHeight; i += 2*CoverAimWindowRadius) + // SphereTrace until no hit is found (free space to aim) + // for (int i = 0; i < MaxCoverAimHeight; i += CoverAimWindowRadius) + // { + // ObstacleTraceStart.Z += i; + // ObstacleTraceEnd.Z += i; + // + // GetWorld()->SweepSingleByChannel( + // Hit, + // ObstacleTraceStart, + // ObstacleTraceEnd, + // FQuat::Identity, + // ObstacleTraceChannel, + // FCollisionShape::MakeSphere(CoverAimWindowRadius), + // QueryParams + // ); + // + // if (bShowCoverSystemDebug) + // { + // DrawDebugSphere(GetWorld(), Hit.Location, CoverAimWindowRadius, 8, + // Hit.bBlockingHit ? FColor::Blue : FColor::Red, + // false, 0.0f, 0, 0); + // } + // + // if (Hit.bBlockingHit == false) + // { + // UE_LOG(LogTemp, Display, TEXT("Free space")); + // bFreeSpace = true; + // break; + // } + // } + + + float SafeCoverAimZOffset = 0.f; + while (SafeCoverAimZOffset < MaxCoverAimHeightOffset) { - ObstacleTraceStart.Z += i; - ObstacleTraceEnd.Z += i; + ObstacleTraceStart.Z += SafeCoverAimZOffset; + ObstacleTraceEnd.Z += SafeCoverAimZOffset; GetWorld()->SweepSingleByChannel( - Hit, - ObstacleTraceStart, - ObstacleTraceEnd, - FQuat::Identity, - ObstacleTraceChannel, - FCollisionShape::MakeSphere(CoverAimWindowRadius), - QueryParams - ); + Hit, + ObstacleTraceStart, + ObstacleTraceEnd, + FQuat::Identity, + ObstacleTraceChannel, + FCollisionShape::MakeSphere(CoverAimWindowRadius), + QueryParams + ); - if (bShowCoverSystemDebug) + if (Hit.bBlockingHit == true) { - DrawDebugSphere(GetWorld(), Hit.Location, CoverAimWindowRadius, 8, - Hit.bBlockingHit ? FColor::Blue : FColor::Red, - false, 0.0f, 0, 0); + // Increment check height every failed iteration + SafeCoverAimZOffset += 0.2f; } - - if (Hit.bBlockingHit == false) + else { - UE_LOG(LogTemp, Display, TEXT("Free space")); - bFreeSpace = true; + // Break the loop if free space found break; } } - - if (bFreeSpace) + + // If this is true that means that free space was found + if (SafeCoverAimZOffset <= MaxCoverAimHeightOffset) { - TargetCoverStandAlpha = FMath::GetMappedRangeValueClamped( - UE::Math::TVector2(GetCharacter()->CrouchedEyeHeight, GetCharacter()->CrouchedEyeHeight + MaxCoverAimHeight), - UE::Math::TVector2(0.0f, 1.0f), - Hit.TraceStart.Z - ); + //// DEBUG //// if (bShowCoverSystemDebug) { - DrawDebugLine(GetWorld(), Hit.TraceStart, Hit.TraceEnd, FColor::Red); + DrawDebugLine(GetWorld(), Hit.TraceStart, Hit.TraceEnd, FColor::Purple); } + ////////////// + + return SafeCoverAimZOffset;// + + //PlayerCharacter->CrouchedEyeHeight - PlayerCharacter->GetCurrentEyeHeight(); } - - - // IDEA FOR A MORE COMPLEX SYSTEM IN THE FUTURE: - //vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - // To not introduce accidental flickering and optimize it a bit, all of this should run - // ONLY on cover update - - // FVector CrouchedEyeWorldPosition = PlayerCharacter->GetActorLocation(); - // CrouchedEyeWorldPosition.Z += PlayerCharacter->CrouchedEyeHeight; - // FVector CoverCeiling = CrouchedEyeWorldPosition + MaxCoverAimHeight; - // float PlayerCapsuleRadius = PlayerCharacter->GetCapsuleComponent()->GetScaledCapsuleHalfHeight(); - // TEnumAsByte ObstacleTraceChannel = ECC_WorldStatic; - // FCollisionQueryParams QueryParams; - // QueryParams.AddIgnoredActor(PlayerCharacter); - // - // // Shoot ray up at maximum cover length to determine how high the player can "stand up" - // FHitResult WallTopHit; - // GetWorld()->SweepSingleByChannel( - // WallTopHit, - // CrouchedEyeWorldPosition, - // CoverCeiling, - // FQuat::Identity, - // ObstacleTraceChannel, - // FCollisionShape::MakeSphere(PlayerCapsuleRadius), - // QueryParams - // ); - // - // FVector CeilingWorldLocation; - // if (WallTopHit.bBlockingHit == true) - // { - // CeilingWorldLocation = WallTopHit.Location; - // } - // else - // { - // CeilingWorldLocation = WallTopHit.TraceEnd; - // } - // - // // From hit location (or if no hit - from end position) shoot ray towards camera's forward - // // vector at minimum cover length - // - // constexpr float WallFinderDistance = 75.0f; - // FVector WallFinderDirection = PlayerCharacter->GetActorForwardVector(); - // WallFinderDirection.Z = 0.0f; // Not needed if the player always stays upright - // - // GetWorld()->LineTraceSingleByChannel( - // WallTopHit, - // CeilingWorldLocation, - // CeilingWorldLocation + (WallFinderDirection * WallFinderDistance), - // ObstacleTraceChannel, - // QueryParams - // ); - // - // // regardless of the hit result shoot multi-ray downwards from end location - // // with maximum cover length - // - // FVector WallTopTraceStart = WallTopHit.bBlockingHit ? WallTopHit.Location : WallTopHit.TraceEnd; - // TArray ValidHitsCandidateArray; - // - // GetWorld()->LineTraceMultiByChannel( - // ValidHitsCandidateArray, - // WallTopTraceStart, - // WallTopTraceStart + (FVector(0.0f, 0.0f, 0.0f) * MaxCoverAimHeight), - // ObstacleTraceChannel, - // QueryParams - // ); - - // On every ray hit trace an in-place sphere to determine if the aiming spot is valid - - // All valid aiming spots are collected and the lowest (smallest Z) is chosen - - // Sphere trace from camera forward a certain distance to regulate camera position while - // aiming up and down // TODO: elaborate + // Return 0 offset if no free space to aim was found + return 0.f; } -void AExoPlayerController::UpdateCoverStandHeight(float DeltaTime) +void AExoPlayerController::UpdateSmoothCoverCamera(float DeltaTime) { - // if (FMath::IsNearlyEqual(CoverStandAlpha, TargetCoverStandAlpha, 0.01f)) - // { - // return; - // } + if (FMath::IsNearlyEqual(CoverStandAlpha, TargetCoverStandAlpha, 0.01f)) + { + return; + } CoverStandAlpha = FMath::Lerp(CoverStandAlpha, TargetCoverStandAlpha, DeltaTime * 5.0f); - //CoverStandAlpha = TargetCoverStandAlpha; // BANDAID SOLUTION const float NewZ = FMath::Lerp( - PlayerCharacter->CrouchedEyeHeight, - PlayerCharacter->StandingEyeHeight, + PlayerCharacter->GetCrouchingEyeHeight(), + PlayerCharacter->GetStandingEyeHeight(), CoverStandAlpha ); @@ -502,6 +488,7 @@ void AExoPlayerController::UpdateCoverStandHeight(float DeltaTime) FVector(0.0f, 0.0f, NewZ) ); + // DEBUG if (bShowCoverSystemDebug && GEngine) { GEngine->AddOnScreenDebugMessage(1, -1, FColor::Red, FString::Printf(TEXT("Current cover stand alpha: %f"), CoverStandAlpha)); @@ -510,11 +497,11 @@ void AExoPlayerController::UpdateCoverStandHeight(float DeltaTime) void AExoPlayerController::OnCoverTimer() { - bIsInCover = CheckForCover(); - if (bIsInCover == false) + PlayerCharacter->bIsInCover = CheckForCover(); + if (PlayerCharacter->bIsInCover == false) { TargetCoverStandAlpha = 0.0f; - UpdateCoverStandHeight(GetWorld()->GetDeltaSeconds()); + UpdateSmoothCoverCamera(GetWorld()->GetDeltaSeconds()); } } diff --git a/Source/Exo/Public/Characters/Components/ShootingComponent.h b/Source/Exo/Public/Characters/Components/ShootingComponent.h index 1c41581..717dfdb 100644 --- a/Source/Exo/Public/Characters/Components/ShootingComponent.h +++ b/Source/Exo/Public/Characters/Components/ShootingComponent.h @@ -99,6 +99,10 @@ public: AGunBase* SecondaryGunBase = nullptr; UStaticMeshComponent* SecondaryGunMesh = nullptr; + DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnADSEventSignature); + FOnADSEventSignature OnStartedADS; + FOnADSEventSignature OnStoppedADS; + private: void ResetFireCooldown(); void ReloadCompleted(); diff --git a/Source/Exo/Public/Characters/ExoPlayerCharacter.h b/Source/Exo/Public/Characters/ExoPlayerCharacter.h index d1e7ffa..02a4a0e 100644 --- a/Source/Exo/Public/Characters/ExoPlayerCharacter.h +++ b/Source/Exo/Public/Characters/ExoPlayerCharacter.h @@ -5,7 +5,6 @@ #include "CoreMinimal.h" #include "Camera/CameraComponent.h" #include "Characters/ExoCharacterBase.h" -#include "Components/CapsuleComponent.h" #include "ExoPlayerCharacter.generated.h" class UInteractionComponent; @@ -32,8 +31,8 @@ public: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Camera") TObjectPtr CameraComponent; - UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Camera") - float StandingEyeHeight; + UPROPERTY(VisibleAnywhere, BlueprintReadOnly) + TObjectPtr CapsuleBottom; UPROPERTY(EditAnywhere, Category = "Dodge Properties") float DodgeForce = 5000.f; @@ -70,13 +69,94 @@ public: int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult ); + UFUNCTION(BlueprintCallable, Category = "Movement") + void CrouchCustom(); + + UFUNCTION(BlueprintCallable, Category = "Movement") + void UnCrouchCustom(); + + DECLARE_MULTICAST_DELEGATE(FOnPlayerCrouchEvent); + FOnPlayerCrouchEvent OnPlayerCrouchStart; + FOnPlayerCrouchEvent OnPlayerCrouchStop; + UFUNCTION() void AddHealthPoints(float addValue); + /** Przekształca wartość relatywną do pozycji środka kapsuły gracza + * na wartość relatywną do pozycji stóp gracza */ + UFUNCTION(BlueprintPure) + float ToFeet(float Value); + + /** Przekształca wartość relatywną do pozycji stóp kapsuły gracza + * na wartość relatywną do pozycji kapsuły gracza */ + UFUNCTION(BlueprintPure) + float FromFeet(float Value); + + UFUNCTION(BlueprintCallable, Category="Camera") + void SetEyePositionOffsetTarget(FVector LocationOffset); + + UFUNCTION(BlueprintCallable, Category="Camera") + void SetEyeRoll(float RollValue); + + UFUNCTION(BlueprintCallable) + FVector GetPlayerLocationAtFeet() const; + + UFUNCTION(BlueprintCallable, Category="Camera") + void SetTargetEyeHeight(float NewEyeHeight, const bool bCapsuleRelative = false); + + UFUNCTION(BlueprintCallable, Category="Camera") + float GetCurrentEyeHeight(const bool bCapsuleRelative = false); + + //UFUNCTION(BlueprintCallable, Category="Camera") + //float GetCurrentEyeHeightBase(const bool bCapsuleRelative = false); + + UFUNCTION(BlueprintPure, Category="Camera") + float GetStandingEyeHeight(const bool bCapsuleRelative = false) const; + + UFUNCTION(BlueprintPure, Category="Camera") + float GetCrouchingEyeHeight(const bool bCapsuleRelative = false) const; + + /** Czy postać gracza jest obecnie schowana za osłoną */ + UPROPERTY(BlueprintReadOnly, Category = "Cover System") + bool bIsInCover = false; + + /** Offset kamery podczas leżenia (osłona, ślizg)
+ * Bezpiecznie będzie założyć że to najniżej jak kamera + * może zejść podczas gameplaya + */ + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Camera") + float LowEyeHeightOffset; + + protected: virtual void BeginPlay() override; + + virtual void Tick(float DeltaTime) override; float MaxHealth = 100.0f; UWBP_PlayerUI* PlayerHud; + + /** Wysokość kamery podczas kucania jest dostarczana przez Character.h*/ + /** Wysokość kamery podczas stania
+ * Też najwyższa wysokość na którą kamera może się wznieść + * podczas gameplaya + */ + UPROPERTY(EditAnywhere, Category="Camera") + float StandingEyeHeight; + + UFUNCTION(BlueprintCallable) + float GetFootOffset(); + + +private: + FVector TargetEyeLocationOffset; + FVector EyeLocationOffset; + float TargetEyeRoll; + float EyeRoll; + + float TargetEyeHeight; + + void UpdateCameraHeight(float DeltaTime); + void ApplyCameraOffset(float DeltaTime); }; diff --git a/Source/Exo/Public/Player/ExoPlayerController.h b/Source/Exo/Public/Player/ExoPlayerController.h index 159fc63..017f0fb 100644 --- a/Source/Exo/Public/Player/ExoPlayerController.h +++ b/Source/Exo/Public/Player/ExoPlayerController.h @@ -96,16 +96,14 @@ protected: bool CheckForCover(); UFUNCTION(BlueprintCallable, Category = "Cover System") - void AdjustCameraWhileInCover(); + float CalculateCoverAimOffset(); UFUNCTION(BlueprintCallable, Category = "Cover System") - void UpdateCoverStandHeight(float DeltaTime); + void UpdateSmoothCoverCamera(float DeltaTime); void OnCoverTimer(); - float MapAlphaToCoverStandHeight(float Alpha); - - // DEBUG + // Cover System DEBUG UFUNCTION(Exec, Category = "Cover System") void DebugCoverSystem(bool show); bool bShowCoverSystemDebug = false; @@ -176,11 +174,7 @@ protected: UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Character") TObjectPtr PlayerCharacter; - - // Czy postać gracza jest obecnie schowana za osłoną - UPROPERTY(EditAnywhere, Category = "Cover System") - bool bIsInCover = false; - + /** Alpha wysokości kamery podczas wychulania zza osłony * 0 - Wysokość kucania * 1 - Maksymalna wysokość wychylenia określona przez CoverAimStandFactor @@ -188,32 +182,40 @@ protected: UPROPERTY(EditAnywhere, Category = "Cover System") float TargetCoverStandAlpha = 0.0f; - // Częstotliwość okresowego szukania osłon podczas kucania + /** Częstotliwość okresowego szukania osłon podczas kucania */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cover System") float CoverCheckRate = 0.5f; - // Dystans na którym postać jest w stanie odnaleźć osłonę + /** Dystans na którym postać jest w stanie odnaleźć osłonę */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cover System") float MaxDistanceFromCover = 50.0f; - // Minimalna wysokość przeszkody którą można określić osłoną - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cover System") + /** Używa wysokości oczu do określenia minimalnej wysokości przeszkody + * którą można określić osłoną + */ + UPROPERTY(EditAnywhere, Category = "Cover System") + bool bUseEyeHeight = true; + + /** Minimalna wysokość przeszkody którą można określić osłoną */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cover System", + meta = (EditCondition = "!UseEyeHeight")) float CoverObstacleMinHeight = 75.0f; - // Maksymalna wysokość przeszkody którą można określić osłoną + /** Maksymalna wysokość przeszkody którą można określić osłoną */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cover System") float CoverObstacleMaxHeight = 125.0f; - // Promień wolnej przestrzeni przez którą można się wychylić + /** Promień wolnej przestrzeni przez którą można się wychylić */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cover System") float CoverAimWindowRadius = 2.0f; - // Dystans od kamery po wychyleniu który musi być wolny by dało się wychylić + /** Dystans od kamery po wychyleniu który musi być wolny by dało się wychylić */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cover System") float CoverAimFreeDistance = 150.0f; /** Określa na jaki procent "Stania" postać może się podnieść podczas celowania - * zza osłony. 0 -> Nie podniesie się wogóle (jakby wychylanie się było wyłączone) + * zza osłony.
+ * 0 -> Nie podniesie się wogóle (jakby wychylanie się było wyłączone)
* 1 -> Postać jest w stanie się podnieść do pełnej wysokości, tak jakby normalnie stała **/ UPROPERTY(EditAnywhere, @@ -229,10 +231,18 @@ protected: private: UInteractionComponent* InteractionComponent; - + UShootingComponent* ShootingComponent; - float CoverStandAlpha = 0.0f; + + + float CoverStandAlpha = 0.0f; // deprecated FTimerHandle CoverCheckTimer; - float MaxCoverAimHeight; + float MaxCoverAimHeightOffset; + float CoverAimHeightOffset; + + + + //FTransform TargetCameraOffset; + //FTransform CameraOffset; };