// Fill out your copyright notice in the Description page of Project Settings. #include "Rover.h" #include "InputAction.h" #include "InputActionValue.h" #include "InputMappingContext.h" #include "EnhancedInputSubsystems.h" #include "EnhancedInputComponent.h" #include "RoverController.h" #include "Kismet/GameplayStatics.h" #include "CesiumGlobeAnchorComponent.h" #include "Kismet/KismetMathLibrary.h" #include "CesiumGeoreference.h" #include "Camera/CameraComponent.h" #include "GameFramework/SpringArmComponent.h" #include "DrawDebugHelpers.h" #include "Blueprint/UserWidget.h" #include "CesiumFlyToComponent.h" #include "GameFramework/PawnMovementComponent.h" #include "Blueprint/WidgetLayoutLibrary.h" #include "Engine/StaticMeshActor.h" #include "Components/SceneCaptureComponent2D.h" #include "ConvexVolume.h" ARover* ARover::PlayerPawn = nullptr; ARover::ARover(): bPressMouseMiddleKey(false), SelfBaseTurnRate(10), SelfBaseLookUpRate(10), ZoomRollSpeed(5.f), RotateAngle(0.1f), bPressMouseRightKey(false), bPressMouseLeftKey(false), BaseMouseLeftMoveRate(50.f), MoveToLocation(FVector(0)), MaxDistance(1.f), bMoveForward(false), bMoveRight(false), bLimitViewport(false), bAllowMouseLeftMove(true), ControlHeightMulitiplier(0.1f), LongitudeLatitudeControlHeightMulitiplier(0.01), MouseMoveOffsetMulitiplier(0.01), bAllowUpdataMove(false), SlowStopMoveSpeed(0), TotalSlowStopMoveOffsetTime(0), CurrentSlowStopMoveOffsetTime(0), ChangeHeightThreshold(100000), bFlying(false), ZoomOffsetMulitiplier(0.1f), ZoomOffsetHeightValue(1000000), bFollowSportTrace(false), CurrentMoveDistance(0), MoveSpeedMultiplier(1.5f), bAllowInertialMove(false), CheckMoveCollisionChannel(ECollisionChannel::ECC_Visibility), SelecteItemMode(ESelecteItemMode::ESM_Default), LastSelecteItemMode(ESelecteItemMode::ESM_Default), bTempStopAutoRotate(false) { PlayerPawn = this; FlyComp = CreateDefaultSubobject(TEXT("FlyComp")); FlyComp->RotationToUse = ECesiumFlyToRotation::ControlRotationInUnreal; FlyComp->Duration = 3.f; SpringArm = CreateDefaultSubobject(TEXT("SpringArmComp")); SpringArm->SetupAttachment(RootComponent); Camera = CreateDefaultSubobject(TEXT("CameraComp")); Camera->SetupAttachment(SpringArm); AutoPossessPlayer = EAutoReceiveInput::Player0; } void ARover::Tick(float DeltaTime) { Super::Tick(DeltaTime); PlayerLongitudeLatitudeHeight = GlobeAnchor->GetLongitudeLatitudeHeight(); LastMousePosition = MousePosition; PlayerController->GetMousePosition(MousePosition.X, MousePosition.Y); UpdataMoveToLocation(DeltaTime); if (GlobeAnchor->GetHeight() > 100000) { if (PlayerController) { //PlayerController->GetMainHUD()->CloseWeatherSystem(); } } UpdateSlideRotation(DeltaTime); InertialMove(DeltaTime); //GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::White, TEXT("Tick正在执行")); } void ARover::BeginPlay() { Super::BeginPlay(); PlayerController = Cast(UGameplayStatics::GetPlayerController(GetWorld(), 0)); if (Georeference) { FVector Location = Georeference->TransformLongitudeLatitudeHeightPositionToUnreal(FVector(106.405113, 29.720642, 7000000.0)); CurrentHeight = 7000000.0; SetActorLocation(Location); PlayerController->SetControlRotation(FRotator(-88.f, -90, 0)); Georeference->SetOriginLongitudeLatitudeHeight(FVector(106, 30, 1000.0)); } } void ARover::SetupPlayerInputComponent(UInputComponent* InInputComponent) { if (APlayerController* ThePlayerController = Cast(GetController())) { if (UEnhancedInputLocalPlayerSubsystem* LocalPlayerSubsystem = ULocalPlayer::GetSubsystem(ThePlayerController->GetLocalPlayer())) { LocalPlayerSubsystem->AddMappingContext(BaseInputAction, 0); } } if (UEnhancedInputComponent* EnhancedInputComponent = Cast(InInputComponent)) { if (MouseMiddleAxisAsset) { EnhancedInputComponent->BindAction(MouseMiddleAxisAsset, ETriggerEvent::Started, this, &ARover::PressMouseMiddleButton); EnhancedInputComponent->BindAction(MouseMiddleAxisAsset, ETriggerEvent::Completed, this, &ARover::ReleaseMouseMiddleButton); } if (MouseLeftAsset) { EnhancedInputComponent->BindAction(MouseLeftAsset, ETriggerEvent::Started, this, &ARover::PressMouseLeftButton); EnhancedInputComponent->BindAction(MouseLeftAsset, ETriggerEvent::Completed, this, &ARover::ReleaseMouseLeftButton); EnhancedInputComponent->BindAction(MouseLeftAsset, ETriggerEvent::Triggered, this, &ARover::MouseLeftMovePawn); } if (TurnAsset) { EnhancedInputComponent->BindAction(TurnAsset, ETriggerEvent::Triggered, this, &ARover::_TurnAtRate); } if (LookUpAsset) { EnhancedInputComponent->BindAction(LookUpAsset, ETriggerEvent::Triggered, this, &ARover::_LookUpAtRate); } if (GamePadTurnAsset) { EnhancedInputComponent->BindAction(GamePadTurnAsset, ETriggerEvent::Triggered, this, &ARover::GamePadTurnAtRate); } if (GamePadLookUPAsset) { EnhancedInputComponent->BindAction(GamePadLookUPAsset, ETriggerEvent::Triggered, this, &ARover::GamePadLookUpAtRate); } if (MouseRollAxisAsset) { EnhancedInputComponent->BindAction(MouseRollAxisAsset, ETriggerEvent::Triggered, this, &ARover::MouseRollDistance); } if (MouseRightAsset) { EnhancedInputComponent->BindAction(MouseRightAsset, ETriggerEvent::Started, this, &ARover::PressMouseRightButton); EnhancedInputComponent->BindAction(MouseRightAsset, ETriggerEvent::Completed, this, &ARover::ReleaseMouseRightButton); } if (MoveForwardAsset) { EnhancedInputComponent->BindAction(MoveForwardAsset, ETriggerEvent::Triggered, this, &ARover::_MoveForward); EnhancedInputComponent->BindAction(MoveForwardAsset, ETriggerEvent::Completed, this, &ARover::ReleaseMoveButton); } if (MoveRightAsset) { EnhancedInputComponent->BindAction(MoveRightAsset, ETriggerEvent::Triggered, this, &ARover::_MoveRight); EnhancedInputComponent->BindAction(MoveRightAsset, ETriggerEvent::Completed, this, &ARover::ReleaseMoveButton); } if (TS_TwoTouchAsset) { EnhancedInputComponent->BindAction(TS_TwoTouchAsset, ETriggerEvent::Triggered, this, &ARover::TS_TriggeredTwoTouch); EnhancedInputComponent->BindAction(TS_TwoTouchAsset, ETriggerEvent::Started, this, &ARover::TS_PressTwoTouch); EnhancedInputComponent->BindAction(TS_TwoTouchAsset, ETriggerEvent::Completed, this, &ARover::TS_ReleaseTwoTouch); } } } void ARover::PressMouseMiddleButton() { if (bPressMouseLeftKey || bPressMouseRightKey)return; bPressMouseMiddleKey = true; } void ARover::ReleaseMouseMiddleButton() { bPressMouseMiddleKey = false; } void ARover::PressMouseLeftButton() { FHitResult _ClickObject; if ( bPressMouseMiddleKey)return; if (bCurrentLookingup) { ReleaseMouseMiddleButton(); bCurrentLookingup = false; } if (bHDRIMode) { PressMouseMiddleButton(); return; } PlayerController->GetMousePosition(TestMousePosition.X, TestMousePosition.Y); FHitResult _HitResult; if (PlayerController->GetUnderMouseHitPosition(_HitResult)) { MouseClickLongitudeLatitude = Georeference->TransformUnrealPositionToLongitudeLatitudeHeight(_HitResult.Location); if (GlobeAnchor->GetHeight() < 20000) { AssistMouseLeftMoveActor->SetActorLocation(_HitResult.Location); float _Distance = (AssistMouseLeftMoveActor->GetActorLocation() - GetActorLocation()).Length() * 0.1; AssistMouseLeftMoveActor->SetActorScale3D(FVector(_Distance)); CheckMoveCollisionChannel = ECollisionChannel::ECC_GameTraceChannel1; } else { CheckMoveCollisionChannel = ECollisionChannel::ECC_Visibility; } } bPressMouseLeftKey = true; } void ARover::ReleaseMouseLeftButton() { if (bHDRIMode) { ReleaseMouseMiddleButton(); return; } bPressMouseLeftKey = false; if (!bAllowUpdataMove)bAllowInertialMove = true; } void ARover::PressMouseRightButton() { if (bPressMouseLeftKey || bPressMouseMiddleKey)return; if (bHDRIMode) { PressMouseMiddleButton(); return; } bTempStopAutoRotate = true; bPressMouseRightKey = true; // 用于判断当前右键是拖动还是点击 //FTimerHandle ClearSelectedResourceItemTimer; //GetWorldTimerManager().SetTimer(ClearSelectedResourceItemTimer, this, &ARover::ClearSelectedResourceItemSets, 0.2f, false); StopMouseLeftMove(); UpdatascreenCenterPointLocation(); } void ARover::ReleaseMouseRightButton() { bTempStopAutoRotate = false; bPressMouseRightKey = false; //PlayerController->SetMouseShowStatus(true); bLimitViewport = false; AdjustSpeedByHeight(); if (LastMousePosition != MousePosition) { SlideTime = (MousePosition - LastMousePosition).Length() * MouseMoveOffsetMulitiplier * 0.1;; TotalSlideTime = SlideTime; GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::SanitizeFloat(SlideTime)); } } void ARover::_TurnAtRate(const FInputActionValue& Value) { if (bPressMouseRightKey) { AroundPointRotation(Value.GetMagnitude(), EAxis::X); } if (!bPressMouseMiddleKey)return; AddControllerYawInput(Value.GetMagnitude() * GetWorld()->GetDeltaSeconds() * SelfBaseTurnRate * -0.15 * Camera->FieldOfView / 80); } void ARover::GamePadTurnAtRate(const FInputActionValue& Value) { if (bFollowSportTrace)return; AddControllerYawInput(Value.GetMagnitude() * GetWorld()->GetDeltaSeconds() * SelfBaseTurnRate * -0.15 * Camera->FieldOfView / 80); } void ARover::_LookUpAtRate(const FInputActionValue& Value) { if (bPressMouseRightKey) { AroundPointRotation(Value.GetMagnitude(), EAxis::Y); } if (!bPressMouseMiddleKey)return; AddControllerPitchInput(Value.GetMagnitude() * GetWorld()->GetDeltaSeconds() * SelfBaseLookUpRate * 0.15 * Camera->FieldOfView / 80); } void ARover::GamePadLookUpAtRate(const FInputActionValue& Value) { AddControllerPitchInput(Value.GetMagnitude() * GetWorld()->GetDeltaSeconds() * SelfBaseLookUpRate * 0.15 * Camera->FieldOfView / 80); } void ARover::MouseRollDistance(const FInputActionValue& Value) { if (!bHDRIMode) { AssistMouseRollDistance(Value.GetMagnitude()); } else { //输出鼠标滚轮值 MiddleKeyValue = Value.GetMagnitude(); } } void ARover::TS_TriggeredTwoTouch(const FInputActionValue& Value) { if (!bTS_StartAction)return; LastTouch1 = Touch1; LastTouch2 = Touch2; PlayerController->GetInputTouchState(ETouchIndex::Touch1, Touch1.X, Touch1.Y, bPressTouch1); PlayerController->GetInputTouchState(ETouchIndex::Touch2, Touch2.X, Touch2.Y, bPressTouch2); if (LastTouch1 == Touch1 && LastTouch2 == Touch2)return; FVector2D CurTwoTouchDirection = (Touch1 - LastTouch1).GetSafeNormal(); FVector2D LastTwoTouchDirection = (Touch2 - LastTouch2).GetSafeNormal(); double Delta = UKismetMathLibrary::DotProduct2D(CurTwoTouchDirection, LastTwoTouchDirection); if (Delta <= 0) { TS_MouseRollDistance(Value); TS_FOVRotation(Value); } else if (Delta > 0) { TS_UpDownPitch(Value); } } void ARover::TS_MouseRollDistance(const FInputActionValue& Value) { if (!bPressTouch1 || !bPressTouch1)return; float TheValue = ((Touch1 - Touch2).Length() - ((LastTouch1 - LastTouch2).Length())) * 0.05; AssistMouseRollDistance(TheValue, TS_ZoomHitResult); } void ARover::TS_PressTwoTouch() { if (GetWorldTimerManager().IsTimerActive(TS_DelayReleaseTimer)) { GetWorldTimerManager().ClearTimer(TS_DelayReleaseTimer); } bTS_PressTwoTouch = true; PlayerController->GetInputTouchState(ETouchIndex::Touch1, Touch1.X, Touch1.Y, bPressTouch1); PlayerController->GetInputTouchState(ETouchIndex::Touch2, Touch2.X, Touch2.Y, bPressTouch2); if (TS_ZoomHitResult == std::nullopt) { FVector2D TS_ZoomPoint = (Touch1 + Touch2) * 0.5f; FHitResult HitResult; PlayerController->GetUnderScreenHitPosition(TS_ZoomPoint, HitResult); TS_ZoomHitResult = HitResult; } GetWorldTimerManager().SetTimer(TS_ActionTimer, this, &ARover::TS_StartAction, TS_DelayTime, false); } void ARover::TS_ReleaseTwoTouch() { if (GetWorldTimerManager().IsTimerActive(TS_DelayReleaseTimer)) { GetWorldTimerManager().ClearTimer(TS_DelayReleaseTimer); } FTimerDelegate _TimerDelegate; _TimerDelegate.BindLambda([this]() { this->bTS_PressTwoTouch = false; this->bLimitViewport = false; this->bTS_StartAction = false; this->TS_ZoomHitResult = std::nullopt; this->TS_ActionStatus = ETSAction::ETS_Default; }); GetWorldTimerManager().SetTimer(TS_DelayReleaseTimer, _TimerDelegate, 0.05f, false); } void ARover::TS_FOVRotation(const FInputActionValue& Value) { FVector2D CurTwoTouchDirection = (Touch2 - Touch1).GetSafeNormal(); FVector2D LastTwoTouchDirection = (LastTouch2 - LastTouch1).GetSafeNormal(); if (LastTouch1 == Touch1 && LastTouch2 == Touch2)return; if (!bPressTouch1 || !bPressTouch2)return; float Angle = FMath::RadiansToDegrees(FMath::Acos(UKismetMathLibrary::DotProduct2D(CurTwoTouchDirection, LastTwoTouchDirection) / (CurTwoTouchDirection.Length() * LastTwoTouchDirection.Length()))); float Alpha = SelfBaseTurnRate * 0.5 * Angle; if (UKismetMathLibrary::CrossProduct2D(CurTwoTouchDirection, LastTwoTouchDirection) <= 0) { Alpha *= -1; } AroundPointRotation(Alpha, EAxis::X, TS_ZoomHitResult->Location); } void ARover::TS_UpDownPitch(const FInputActionValue& Value) { if (LastTouch1 == Touch1 && LastTouch2 == Touch2)return; if (!bPressTouch1 || !bPressTouch2)return; FVector2D CurTwoTouchDirection = (Touch2 - Touch1).GetSafeNormal(); FVector2D LastTwoTouchDirection = (LastTouch2 - LastTouch1).GetSafeNormal(); float Alpha = Value.GetMagnitude() * GetWorld()->GetDeltaSeconds() * 0.4; if (LastTouch1.Y - Touch1.Y <= 0) { Alpha *= -1; } AroundPointRotation(Alpha, EAxis::Y, TS_ZoomHitResult->Location); } void ARover::ModifyMaxRollCoefficient(float Coefficient) { MaxRollCoefficient = Coefficient; AssistMouseRollDistance(1); } void ARover::_MoveRight(const FInputActionValue& TheValue) { float Value = TheValue.GetMagnitude(); if (Value && GetController()) { StopMouseLeftMove(); AdjustSpeedByHeight(); FRotator ControlRotation = GetControlRotation(); FRotator Rotation(ControlRotation.Pitch, ControlRotation.Yaw, 0); FVector Direction = FRotationMatrix(Rotation).GetUnitAxis(EAxis::Y); float Height = GlobeAnchor->GetHeight(); if (Height < 50)Height = 50; AddMovementInput(Direction, Value * Height * 0.000001); UpdateOrignLongitudeLatitude(); bPressMoveButton = true; UpdateCurrentHeight(); } } void ARover::UpdateCurrentHeight() { this->CurrentHeight = Georeference->TransformUnrealPositionToLongitudeLatitudeHeight(this->GetActorLocation()).Z; } void ARover::ResetPlayerProperty() { bPressMoveButton = false; } void ARover::MoveToLongitudeLatitudeHeight(const FVector& LongitudeLatitudeHeight) { if (bFlying)return; GlobeAnchor->MoveToLongitudeLatitudeHeight(LongitudeLatitudeHeight); UpdateOrignLongitudeLatitude(); UpdateCurrentHeight(); } void ARover::EnableCameraLag(bool bOpen) { if (bOpen) { SpringArm->bEnableCameraLag = true; SpringArm->bEnableCameraRotationLag = true; } else { SpringArm->bEnableCameraLag = false; SpringArm->bEnableCameraRotationLag = false; } } void ARover::SetMaxRollDistance(float _MaxDistance) { CurrentMaxRollDistance = _MaxDistance; FVector SelfLocation = GetActorLocation(); if (SelfLocation.Z < CurrentMaxRollDistance)return; FHitResult HitResult; if (ARoverController::PlayerController->GetUnderscreenCenterHitPosition(HitResult)) { FVector Direction = (SelfLocation - HitResult.Location).GetSafeNormal(); SelfLocation = HitResult.Location + Direction * CurrentMaxRollDistance; SetActorLocation(SelfLocation); UpdateCurrentHeight(); } } FConvexVolume ARover::GetViewFrustum() { FMinimalViewInfo CameraViewInfo; Camera->GetCameraView(GetWorld()->GetDeltaSeconds(), CameraViewInfo); FMatrix ProjectionMatrix; FMatrix ViewMatrix; FMatrix ViewProjectionMatrix; UGameplayStatics::GetViewProjectionMatrix(CameraViewInfo, ViewMatrix, ProjectionMatrix, ViewProjectionMatrix); FConvexVolume ViewFrustum; GetViewFrustumBounds(ViewFrustum, ViewProjectionMatrix, true, true); return ViewFrustum; } bool ARover::CheckPointInViewFrustum(const FVector& Point) { FConvexVolume ViewFrustum = GetViewFrustum(); TArray Vertices; return ViewFrustum.IntersectPoint(Point); } void ARover::StopKeyMove() { bKeyMove = false; } void ARover::StartKeyMove() { bKeyMove = true; } void ARover::ClearCurrentSlowStopMoveOffsetTime() { CurrentSlowStopMoveOffsetTime = 0; MoveToLocation = FVector(0); } void ARover::TS_StartAction() { UpdatascreenCenterPointLocation(); bTS_StartAction = true; } void ARover::MouseLeftMovePawn(const FInputActionValue& Value) { if (!bPressMouseLeftKey || !bAllowMouseLeftMove || bFollowSportTrace || bTS_PressTwoTouch)return; if (LastMousePosition == MousePosition)return; if (!bCurrentLookingup) { float MouseOffset = (MousePosition - LastMousePosition).Length(); FVector MouseDirection; FVector MousePositionWorldLocation; FVector LastMouseDirection; FVector LastMousePositionWorldLocation; PlayerController->DeprojectScreenPositionToWorld(MousePosition.X, MousePosition.Y, MousePositionWorldLocation, MouseDirection); PlayerController->DeprojectScreenPositionToWorld(LastMousePosition.X, LastMousePosition.Y, LastMousePositionWorldLocation, LastMouseDirection); FVector Location = GetActorLocation(); float Height = FMath::Abs(GlobeAnchor->GetHeight()); if (Height < 200)Height = 200; FHitResult _MouseHitResult; GetWorld()->LineTraceSingleByChannel(_MouseHitResult, MousePositionWorldLocation, MousePositionWorldLocation + MouseDirection * 100000000000, CheckMoveCollisionChannel); if (_MouseHitResult.bBlockingHit) { if (bAllowUpdateSlide) { MouseClickLongitudeLatitude = Georeference->TransformUnrealPositionToLongitudeLatitudeHeight(_MouseHitResult.Location); bAllowUpdateSlide = false; bAllowSlowStopMove = false; return; } bAllowUpdataMove = false; FVector _MouseLocation = _MouseHitResult.Location; FVector _FirstMouseClickPosition = Georeference->TransformLongitudeLatitudeHeightPositionToUnreal(MouseClickLongitudeLatitude); FVector2D _MousescreenPosition; FVector2D _FirstMousescreenPosition; PlayerController->ProjectWorldLocationToScreen(_MouseLocation, _MousescreenPosition); PlayerController->ProjectWorldLocationToScreen(_FirstMouseClickPosition, _FirstMousescreenPosition); _MouseLocation.Z = 0; _FirstMouseClickPosition.Z = 0; MoveDirectionLast = (_MouseLocation - _FirstMouseClickPosition).GetSafeNormal() * -1; CurrentMoveDistance = (_MouseLocation - _FirstMouseClickPosition).Length(); FVector MoveToDistance = MoveDirectionLast * CurrentMoveDistance; MoveToDistance.Z = 0; MoveToLocation = Location + MoveToDistance; FVector TargetLongitudeLatitude = Georeference->TransformUnrealPositionToLongitudeLatitudeHeight(MoveToLocation); float Latitude = TargetLongitudeLatitude.Y; if (Latitude > MaxCrossingLatitude || Latitude < -MaxCrossingLatitude) { FInputActionValue InputActionValue(-10.f); _MoveRight(InputActionValue); } else { TargetLongitudeLatitude.Z = CurrentHeight; MoveToLocation = Georeference->TransformLongitudeLatitudeHeightPositionToUnreal(TargetLongitudeLatitude); GlobeAnchor->MoveToLongitudeLatitudeHeight(TargetLongitudeLatitude); } UpdateOrignLongitudeLatitude(); TotalSlowStopMoveOffsetTime = MouseOffset * MouseMoveOffsetMulitiplier * 0.1; } else if (GlobeAnchor->GetHeight() > LimitValueOfRotateAroundPoint) { bAllowSlowStopMove = true; bAllowUpdateSlide = true; MoveDirectionLast = (MousePositionWorldLocation - LastMousePositionWorldLocation).GetSafeNormal() * -1; FVector MoveToDistance = MoveDirectionLast * (MousePositionWorldLocation - LastMousePositionWorldLocation).Length() * Height * BaseMouseLeftMoveRate * 10; Location += MoveToDistance; FVector MoveToLongitudeLatitude = Georeference->TransformUnrealPositionToLongitudeLatitudeHeight(Location); MoveToLongitudeLatitude.Z = Height; MoveToLocation = MoveToLongitudeLatitude; TotalSlowStopMoveOffsetTime = FMath::Clamp(MouseOffset * MouseMoveOffsetMulitiplier, 0.f, 1.f); if (GetWorldTimerManager().IsTimerActive(SlowStopMoveTimer))GetWorldTimerManager().ClearTimer(SlowStopMoveTimer); GetWorld()->GetTimerManager().SetTimer(SlowStopMoveTimer, this, &ARover::StartSlowStopMove, CurrentSlowStopMoveOffsetTime, false); bAllowUpdataMove = true; } else { bCurrentLookingup = true; PressMouseMiddleButton(); } if (!bCurrentLookingup) { CurrentSlowStopMoveOffsetTime = TotalSlowStopMoveOffsetTime; } } } void ARover::TouchMovePawn(FVector2D CurScreenPosition, FVector2D LastScreenPosition) { if (CurScreenPosition == LastScreenPosition)return; MousePosition = CurScreenPosition; LastMousePosition = LastScreenPosition; float MouseOffset = (CurScreenPosition - LastScreenPosition).Length(); FVector MouseDirection; FVector MousePositionWorldLocation; FVector LastMouseDirection; FVector LastMousePositionWorldLocation; PlayerController->DeprojectScreenPositionToWorld(CurScreenPosition.X, CurScreenPosition.Y, MousePositionWorldLocation, MouseDirection); PlayerController->DeprojectScreenPositionToWorld(LastScreenPosition.X, LastScreenPosition.Y, LastMousePositionWorldLocation, LastMouseDirection); FVector Location = GetActorLocation(); float Height = FMath::Abs(GlobeAnchor->GetHeight()); if (Height < 200)Height = 200; FHitResult _MouseHitResult; GetWorld()->LineTraceSingleByChannel(_MouseHitResult, MousePositionWorldLocation, MousePositionWorldLocation + MouseDirection * 100000000000, CheckMoveCollisionChannel); if (_MouseHitResult.bBlockingHit) { if (bAllowUpdateSlide) { MouseClickLongitudeLatitude = Georeference->TransformUnrealPositionToLongitudeLatitudeHeight(_MouseHitResult.Location); bAllowUpdateSlide = false; bAllowSlowStopMove = false; return; } bAllowUpdataMove = false; FVector _MouseLocation = _MouseHitResult.Location; FVector _FirstMouseClickPosition = Georeference->TransformLongitudeLatitudeHeightPositionToUnreal(MouseClickLongitudeLatitude); FVector2D _MousescreenPosition; FVector2D _FirstMousescreenPosition; PlayerController->ProjectWorldLocationToScreen(_MouseLocation, _MousescreenPosition); PlayerController->ProjectWorldLocationToScreen(_FirstMouseClickPosition, _FirstMousescreenPosition); _MouseLocation.Z = 0; _FirstMouseClickPosition.Z = 0; MoveDirectionLast = (_MouseLocation - _FirstMouseClickPosition).GetSafeNormal() * -1; CurrentMoveDistance = (_MouseLocation - _FirstMouseClickPosition).Length(); FVector MoveToDistance = MoveDirectionLast * CurrentMoveDistance; MoveToDistance.Z = 0; MoveToLocation = Location + MoveToDistance; FVector TargetLongitudeLatitude = Georeference->TransformUnrealPositionToLongitudeLatitudeHeight(MoveToLocation); float Latitude = TargetLongitudeLatitude.Y; if (Latitude > MaxCrossingLatitude || Latitude < -MaxCrossingLatitude) { FInputActionValue InputActionValue(-10.f); _MoveRight(InputActionValue); } else { TargetLongitudeLatitude.Z = CurrentHeight; MoveToLocation = Georeference->TransformLongitudeLatitudeHeightPositionToUnreal(TargetLongitudeLatitude); GlobeAnchor->MoveToLongitudeLatitudeHeight(TargetLongitudeLatitude); } UpdateOrignLongitudeLatitude(); TotalSlowStopMoveOffsetTime = MouseOffset * MouseMoveOffsetMulitiplier * 0.1; } else if (GlobeAnchor->GetHeight() > LimitValueOfRotateAroundPoint) { bAllowSlowStopMove = true; bAllowUpdateSlide = true; MoveDirectionLast = (MousePositionWorldLocation - LastMousePositionWorldLocation).GetSafeNormal() * -1; FVector MoveToDistance = MoveDirectionLast * (MousePositionWorldLocation - LastMousePositionWorldLocation).Length() * Height * BaseMouseLeftMoveRate * 10; Location += MoveToDistance; FVector MoveToLongitudeLatitude = Georeference->TransformUnrealPositionToLongitudeLatitudeHeight(Location); MoveToLongitudeLatitude.Z = Height; MoveToLocation = MoveToLongitudeLatitude; TotalSlowStopMoveOffsetTime = FMath::Clamp(MouseOffset * MouseMoveOffsetMulitiplier, 0.f, 1.f); if (GetWorldTimerManager().IsTimerActive(SlowStopMoveTimer))GetWorldTimerManager().ClearTimer(SlowStopMoveTimer); GetWorld()->GetTimerManager().SetTimer(SlowStopMoveTimer, this, &ARover::StartSlowStopMove, CurrentSlowStopMoveOffsetTime, false); bAllowUpdataMove = true; } else { bCurrentLookingup = true; PressMouseMiddleButton(); } if (!bCurrentLookingup) { CurrentSlowStopMoveOffsetTime = TotalSlowStopMoveOffsetTime; } } void ARover::UpdataMoveToLocation(float DeltaTime) { static FVector LastTargetLocation = FVector(0); if (MoveToLocation == FVector(0))return; if (bAllowUpdataMove) { FVector TargetLocation = FVector(0); if (!bAllowInertialMove) { FVector Location = GlobeAnchor->GetLongitudeLatitudeHeight(); if (Location.X > 90) { if (MoveToLocation.X < 0) { MoveToLocation.X = 180 + (180 + MoveToLocation.X); } } else if (Location.X < -90) { if (MoveToLocation.X > 0) { MoveToLocation.X = MoveToLocation.X - 360; } } TargetLocation = UKismetMathLibrary::VInterpTo(Location, MoveToLocation, DeltaTime, 3.f); /*if (TargetLocation.X > 180) { TargetLocation.X = TargetLocation.X - 360; } else if (TargetLocation.X < -180) { TargetLocation.X = 180 + (TargetLocation.X + 180); }*/ TargetLocation.Z = CurrentHeight; GlobeAnchor->MoveToLongitudeLatitudeHeight(TargetLocation); if (LastTargetLocation != FVector(0)) { MoveDirectionLast = (TargetLocation - LastTargetLocation).GetSafeNormal(); } if (!GetWorldTimerManager().IsTimerActive(UpdateOriginLongitudeLatitdeTimer)) { DelayUpdateOrigin(); } SlowStopMoveSpeed = (TargetLocation - LastTargetLocation).Length(); } LastTargetLocation = TargetLocation; } else if (!bAllowInertialMove && bAllowSlowStopMove) { //return; if (CurrentSlowStopMoveOffsetTime <= 0) { MoveToLocation = FVector(0); SlowStopMoveSpeed = 0; MoveDirectionLast = FVector(0); LastTargetLocation = FVector(0); bAllowSlowStopMove = false; return; } float SpeedMulityplier = UKismetMathLibrary::NormalizeToRange(CurrentSlowStopMoveOffsetTime, 0, TotalSlowStopMoveOffsetTime); CurrentSlowStopMoveOffsetTime -= DeltaTime; FVector Location = GlobeAnchor->GetLongitudeLatitudeHeight(); FVector TargetLocation = Location + MoveDirectionLast * SlowStopMoveSpeed * SpeedMulityplier; /*if (TargetLocation.X > 180) { TargetLocation.X = TargetLocation.X - 360; } else if (TargetLocation.X < -180) { TargetLocation.X = TargetLocation.X + 360; }*/ /*if (TargetLocation.Y > 90) { TargetLocation.Y = TargetLocation.Y - 180; } else if (TargetLocation.Y < -90) { TargetLocation.Y = TargetLocation.Y + 180; }*/ TargetLocation.Z = CurrentHeight; GlobeAnchor->MoveToLongitudeLatitudeHeight(TargetLocation); if (!GetWorldTimerManager().IsTimerActive(UpdateOriginLongitudeLatitdeTimer)) { DelayUpdateOrigin(); } } } void ARover::_MoveForward(const FInputActionValue& TheValue) { float Value = TheValue.GetMagnitude(); if (Value && GetController()) { StopMouseLeftMove(); AdjustSpeedByHeight(); FRotator ControlRotation = GetControlRotation(); FRotator Rotation(ControlRotation.Pitch, ControlRotation.Yaw, 0); FVector Direction = FRotationMatrix(Rotation).GetUnitAxis(EAxis::X); float Height = GlobeAnchor->GetHeight(); if (Height < 50)Height = 50; else if (Height > 10001620 && Value < 0)Height = 0; AddMovementInput(Direction, Value * Height * 0.000001); if ((GetActorLocation() - screenMiddleLocation).Length() > 8000000)return; UpdateOrignLongitudeLatitude(); bPressMoveButton = true; UpdateCurrentHeight(); } } void ARover::ReleaseMoveButton() { bPressMoveButton = false; } void ARover::StopMoveForward() { bMoveForward = false; ForwardDirection = FVector(0); } void ARover::StopMoveRight() { bMoveRight = false; RightDirection = FVector(0); } void ARover::AllowLeftMouseMovePlayer(bool bAllow) { bAllowMouseLeftMove = bAllow; if (!bAllowMouseLeftMove)MoveToLocation = FVector(0); } bool ARover::GetKeyMoveState() { return bKeyMove; } void ARover::UpdateSlideRotation(float DeltaTime) { if (bPressMouseRightKey) return; if (SlideTime <= 0)return; GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::White, TEXT("正在Tick旋转")); SlideTime -= DeltaTime; float ScaleValue = UKismetMathLibrary::NormalizeToRange(SlideTime, 0, TotalSlideTime); float _SlideSpeed = SlideSpeed * ScaleValue; AroundPointRotation(_SlideSpeed, EAxis::X); } void ARover::UpdateOrignLongitudeLatitude(float Time) { CheckUpdateOrignLongitudeLatitude(); } void ARover::FlyTo(const FVector& LongitudeLatitude, double YawAtDestination, double PitchAtDestination) { if (bFlying) { FlyComp->InterruptFlight(); } StopMouseLeftMove(); OnFlyStart(LongitudeLatitude, YawAtDestination, PitchAtDestination); FlyComp->FlyToLocationLongitudeLatitudeHeight(LongitudeLatitude, YawAtDestination, PitchAtDestination, true); //CheckUpdateOrignLongitudeLatitude(); if (GetWorldTimerManager().IsTimerActive(UpdateFlyOriginTimer))GetWorldTimerManager().ClearTimer(UpdateFlyOriginTimer); GetWorldTimerManager().SetTimer(UpdateFlyOriginTimer, this, &ARover::CheckUpdateOrignLongitudeLatitude, 0.01f, true); bFlying = true; } void ARover::AssistMouseRollDistance(float Value, const FVector2D& ZoomScreenPosition) { std::optional< FVector2D> _ZoomScreenPosition; if (ZoomScreenPosition != FVector2D(-1)) { _ZoomScreenPosition = ZoomScreenPosition; } AssistMouseRollDistance(Value, std::nullopt, _ZoomScreenPosition); } void ARover::AssistMouseRollDistance(float Value, std::optional _TS_ZoomHitResult, std::optional ZoomScreenPosition) { StopMouseLeftMove(); FVector2D ZoomRollPosition; if (ZoomScreenPosition.has_value()) { ZoomRollPosition = ZoomScreenPosition.value(); } else { PlayerController->GetMousePosition(ZoomRollPosition.X, ZoomRollPosition.Y); } FVector ActorLocation = GetActorLocation(); float Height = GlobeAnchor->GetHeight(); FVector WorldLocation; FVector WorldDirection; if (bFollowSportTrace) { FVector2D screenCenter = ARoverController::GetScreenCenterPosition(); PlayerController->DeprojectScreenPositionToWorld(screenCenter.X, screenCenter.Y, WorldLocation, WorldDirection); } else { if (_TS_ZoomHitResult == std::nullopt) { PlayerController->DeprojectScreenPositionToWorld(ZoomRollPosition.X, ZoomRollPosition.Y, WorldLocation, WorldDirection); } else if (_TS_ZoomHitResult->bBlockingHit) { WorldDirection = (_TS_ZoomHitResult->Location - GetActorLocation()).GetSafeNormal(); } } if (Value < 0) { if (ActorLocation.Z >= CurrentMaxRollDistance * MaxRollCoefficient)return; WorldDirection *= -1; } float Speed = 0; FHitResult UnderMouseHitResult; if (_TS_ZoomHitResult == std::nullopt) { PlayerController->GetHitResultAtScreenPosition(ZoomRollPosition, ECollisionChannel::ECC_Visibility, true, UnderMouseHitResult); } else { UnderMouseHitResult.bBlockingHit = _TS_ZoomHitResult->bBlockingHit; UnderMouseHitResult.Location = _TS_ZoomHitResult->Location; } if (UnderMouseHitResult.bBlockingHit) { float TargetPointWithSelfDistance = (UnderMouseHitResult.Location - GetActorLocation()).Length(); Speed = TargetPointWithSelfDistance * ZoomRollSpeed * 0.01; if (Value > 0 && (UnderMouseHitResult.Location - GetActorLocation()).Length() < 50)return; } else { Speed = Height * ZoomRollSpeed; } ActorLocation += WorldDirection * Speed * FMath::Abs(Value); if (ActorLocation.Z > CurrentMaxRollDistance * MaxRollCoefficient) { ActorLocation.Z = CurrentMaxRollDistance * MaxRollCoefficient; } if (Value > 0) { FVector2D screenCenterPosition = ARoverController::GetScreenCenterPosition(); if ((screenCenterPosition - ZoomRollPosition).Length() > 300) { if (Height > ZoomOffsetHeightValue) { FHitResult MouseHitResult; if (PlayerController->GetUnderScreenHitPosition(ZoomRollPosition, MouseHitResult)) { FHitResult screenHitResult; if (PlayerController->GetUnderscreenCenterHitPosition(screenHitResult)) { float Distance = (MouseHitResult.Location - screenHitResult.Location).Length(); FVector Direction = (MouseHitResult.Location - screenHitResult.Location).GetSafeNormal(); ActorLocation += Direction * Distance * ZoomOffsetMulitiplier; } } } } } if (GetWorldTimerManager().IsTimerActive(PlayerController->RotateCameraTimer)) { if ((ActorLocation - screenMiddleLocation).Length() > 5000000 && Value < 0)return; } SetActorLocation(ActorLocation); CurrentHeight = Georeference->TransformUnrealPositionToLongitudeLatitudeHeight(ActorLocation).Z; AdjustSpeedByHeight(); UpdateOrignLongitudeLatitude(); } FVector ARover::GetCurrentLongitudeLatitude() { return FVector(); } void ARover::CheckUpdateOrignLongitudeLatitude() { if (!IsUpdateOrignLongitudeLatitude)return; if (GetWorldTimerManager().IsTimerActive(PlayerController->RotateCameraTimer) || Georeference == nullptr)return; FVector OriginLongitudeLatitude = Georeference->GetOriginLongitudeLatitudeHeight(); FVector SelfLongitudeLatitude = GlobeAnchor->GetLongitudeLatitudeHeight(); SelfLongitudeLatitude.Z = OriginLongitudeLatitude.Z; if (FMath::FloorToInt32(OriginLongitudeLatitude.X) != FMath::FloorToInt32(SelfLongitudeLatitude.X) || FMath::FloorToInt32(OriginLongitudeLatitude.Y) != FMath::FloorToInt32(SelfLongitudeLatitude.Y)) { int32 Lon = FMath::FloorToInt32(SelfLongitudeLatitude.X / 1.f); int32 Lat = FMath::FloorToInt32(SelfLongitudeLatitude.Y / 1.f); Georeference->SetOriginLongitudeLatitudeHeight(FVector(Lon * 1, Lat * 1, SelfLongitudeLatitude.Z)); UpdateOriginCoordinate(); } } float ARover::GetHeight() const { return GlobeAnchor->GetHeight(); } void ARover::AroundPointRotation(float TheValue, EAxis::Type AxisType, FVector _RotationPoint) { if (!IsEnabledAroundPointRotation)return; if (GlobeAnchor->GetHeight() > LimitValueOfRotateAroundPoint || bPressMoveButton) { if (bPressMoveButton) { if (GetWorldTimerManager().IsTimerActive(ReleaseMoveButtonTimer)) { GetWorldTimerManager().ClearTimer(ReleaseMoveButtonTimer); } FTimerDelegate Delegate; Delegate.BindLambda([this]() { bPressMoveButton = false; }); GetWorldTimerManager().SetTimer(ReleaseMoveButtonTimer, Delegate, 0.1f, false); } return; } // 停止移动 MoveToLocation = FVector(0); FVector MovePoint = FVector(0); FRotator ViewRotation(0); FVector RotationPointLocation = _RotationPoint != FVector(-1) ? _RotationPoint : screenMiddleLocation; if (AxisType == EAxis::X) { FVector Vector = GetActorLocation() - RotationPointLocation; float Angle = RotateAngle * TheValue; FVector p = Vector.RotateAngleAxis(Angle, FVector::UpVector); MovePoint = (p + RotationPointLocation); ViewRotation = GetControlRotation(); ViewRotation.Pitch = FMath::UnwindDegrees(ViewRotation.Pitch); ViewRotation.Yaw += Angle; //PlayerController->SetControlRotation(Rotation); } else { FVector ActorLocation = GetActorLocation(); FVector CurrentMoveAixs = ActorLocation - RotationPointLocation; ActorLocation.Z = RotationPointLocation.Z; FVector BaseAxis = ActorLocation - RotationPointLocation; FVector RotateAxis = BaseAxis.RotateAngleAxis(90.f, FVector::UpVector); float Angle = RotateAngle * TheValue; FVector FinishAxis = CurrentMoveAixs.RotateAngleAxis(Angle, RotateAxis.GetSafeNormal()); FVector FinishDirectionAixs = FinishAxis.GetSafeNormal(); // 判断是否是同方向 float SameDirection = UKismetMathLibrary::Dot_VectorVector(FinishDirectionAixs, RotationPointLocation.UpVector); if (SameDirection >= 0.999 && SameDirection <= 1.f) { if (bLimitViewport) { return; } } else { bLimitViewport = true; } MovePoint = FinishAxis + RotationPointLocation; ViewRotation = (RotationPointLocation - MovePoint).Rotation(); if (FMath::Abs(ViewRotation.Pitch) > FMath::Abs(GetControlRotation().Pitch)) { if (FMath::Abs(ViewRotation.Pitch) >= 89)return; } } FVector SelfActorLocation = GetActorLocation(); FHitResult HitResult; FCollisionQueryParams QueryParam; QueryParam.AddIgnoredActor(this); if (GetWorld()->LineTraceSingleByChannel(HitResult, SelfActorLocation, MovePoint, ECollisionChannel::ECC_Visibility, QueryParam)) { return; //MovePoint =HitResult.Location + HitResult.Location.UpVector.GetSafeNormal() * 100; } if (ViewRotation.Pitch > 0)return; SetActorLocation(MovePoint); PlayerController->SetControlRotation(ViewRotation); UpdateCurrentHeight(); } void ARover::UpdatascreenCenterPointLocation() { FHitResult HitResult; FVector ScreenCenterLocation; FVector ScreenCenterDirection; FVector2D ScreenCenterPosition = ARoverController::GetScreenCenterPosition(); PlayerController->DeprojectScreenPositionToWorld(ScreenCenterPosition.X, ScreenCenterPosition.Y, ScreenCenterLocation, ScreenCenterDirection); FVector End = ScreenCenterLocation + ScreenCenterDirection * 100000000; if (GetWorld()->LineTraceSingleByChannel(HitResult, ScreenCenterLocation, End, ECollisionChannel::ECC_Visibility)) { screenMiddleLocation = HitResult.Location; } } void ARover::AdjustSpeedByHeight() { UpdateCurrentHeight(); BaseMouseLeftMoveRate = GlobeAnchor->GetHeight() * LongitudeLatitudeControlHeightMulitiplier; BaseMouseLeftMoveRate = FMath::Clamp(BaseMouseLeftMoveRate, 200, 3000); } void ARover::StartSlowStopMove() { bAllowUpdataMove = false; } void ARover::StopMouseLeftMove() { bAllowUpdataMove = false; CurrentSlowStopMoveOffsetTime = 0; bAllowInertialMove = false; } void ARover::DelayUpdateOrigin(float DelayTime) { if (!GetWorldTimerManager().IsTimerActive(UpdateOriginLongitudeLatitdeTimer)) { FTimerDelegate TimerDelegate; TimerDelegate.BindUFunction(this, TEXT("UpdateOrignLongitudeLatitude"), 0.01f); GetWorld()->GetTimerManager().SetTimer(UpdateOriginLongitudeLatitdeTimer, TimerDelegate, DelayTime, false); } } void ARover::InertialMove(float DeltaTime) { if (!bAllowInertialMove || GlobeAnchor->GetHeight() > ChangeHeightThreshold)return; if (CurrentSlowStopMoveOffsetTime <= 0) { CurrentSlowStopMoveOffsetTime = 0; bAllowInertialMove = false; return; } CurrentSlowStopMoveOffsetTime -= DeltaTime; float SpeedMulityplier = UKismetMathLibrary::NormalizeToRange(CurrentSlowStopMoveOffsetTime, 0, TotalSlowStopMoveOffsetTime); FVector Location = GetActorLocation(); FVector TargetLocation = Location + MoveDirectionLast * CurrentMoveDistance * 0.3 * SpeedMulityplier; FVector TargetLontitudeLatitude = Georeference->TransformUnrealPositionToLongitudeLatitudeHeight(TargetLocation); float Latitude = TargetLontitudeLatitude.Y; if (!(Latitude > MaxCrossingLatitude || Latitude < -MaxCrossingLatitude)) { TargetLontitudeLatitude.Z = CurrentHeight; TargetLocation = Georeference->TransformLongitudeLatitudeHeightPositionToUnreal(TargetLontitudeLatitude); SetActorLocation(TargetLocation); } UpdateOrignLongitudeLatitude(); }