// Copyright Epic Games, Inc. All Rights Reserved. #include "UTAD_UIPlayerController.h" #include "GameFramework/Pawn.h" #include "Blueprint/AIBlueprintHelperLibrary.h" #include "NiagaraSystem.h" #include "NiagaraFunctionLibrary.h" #include "UTAD_UICharacter.h" #include "Engine/World.h" #include "EnhancedInputComponent.h" #include "InputActionValue.h" #include "EnhancedInputSubsystems.h" #include "Engine/LocalPlayer.h" #include "Blueprint/UserWidget.h" DEFINE_LOG_CATEGORY(LogTemplateCharacter); AUTAD_UIPlayerController::AUTAD_UIPlayerController() { bShowMouseCursor = true; DefaultMouseCursor = EMouseCursor::Default; CachedDestination = FVector::ZeroVector; FollowTime = 0.f; } void AUTAD_UIPlayerController::BeginPlay() { // Call the base class Super::BeginPlay(); // Create and show the main HUD ShowMainHUD(); } void AUTAD_UIPlayerController::SetupInputComponent() { // set up gameplay key bindings Super::SetupInputComponent(); // Add Input Mapping Context if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem( GetLocalPlayer())) { Subsystem->AddMappingContext(DefaultMappingContext, 0); } // Set up action bindings if (UEnhancedInputComponent* EnhancedInputComponent = Cast(InputComponent)) { // Setup mouse input events EnhancedInputComponent->BindAction( SetDestinationClickAction, ETriggerEvent::Started, this, &AUTAD_UIPlayerController::OnInputStarted); EnhancedInputComponent->BindAction( SetDestinationClickAction, ETriggerEvent::Triggered, this, &AUTAD_UIPlayerController::OnSetDestinationTriggered); EnhancedInputComponent->BindAction( SetDestinationClickAction, ETriggerEvent::Completed, this, &AUTAD_UIPlayerController::OnSetDestinationReleased); EnhancedInputComponent->BindAction( SetDestinationClickAction, ETriggerEvent::Canceled, this, &AUTAD_UIPlayerController::OnSetDestinationReleased); // Setup touch input events EnhancedInputComponent->BindAction( SetDestinationTouchAction, ETriggerEvent::Started, this, &AUTAD_UIPlayerController::OnInputStarted); EnhancedInputComponent->BindAction( SetDestinationTouchAction, ETriggerEvent::Triggered, this, &AUTAD_UIPlayerController::OnTouchTriggered); EnhancedInputComponent->BindAction( SetDestinationTouchAction, ETriggerEvent::Completed, this, &AUTAD_UIPlayerController::OnTouchReleased); EnhancedInputComponent->BindAction( SetDestinationTouchAction, ETriggerEvent::Canceled, this, &AUTAD_UIPlayerController::OnTouchReleased); // Setup skill tree input if (OpenSkillTreeAction) { EnhancedInputComponent->BindAction( OpenSkillTreeAction, ETriggerEvent::Started, this, &AUTAD_UIPlayerController::OnOpenSkillTree); } } else { UE_LOG( LogTemplateCharacter, Error, TEXT( "'%s' Failed to find an Enhanced Input Component! This template is built to use the Enhanced Input system. If you intend to use the legacy system, then you will need to update this C++ file."), *GetNameSafe(this)); } } void AUTAD_UIPlayerController::OnInputStarted() { StopMovement(); } // Triggered every frame when the input is held down void AUTAD_UIPlayerController::OnSetDestinationTriggered() { // We flag that the input is being pressed FollowTime += GetWorld()->GetDeltaSeconds(); // We look for the location in the world where the player has pressed the // input FHitResult Hit; bool bHitSuccessful = false; if (bIsTouch) { bHitSuccessful = GetHitResultUnderFinger( ETouchIndex::Touch1, ECollisionChannel::ECC_Visibility, true, Hit); } else { bHitSuccessful = GetHitResultUnderCursor( ECollisionChannel::ECC_Visibility, true, Hit); } // If we hit a surface, cache the location if (bHitSuccessful) { CachedDestination = Hit.Location; } // Move towards mouse pointer or touch APawn* ControlledPawn = GetPawn(); if (ControlledPawn != nullptr) { FVector WorldDirection = (CachedDestination - ControlledPawn->GetActorLocation()) .GetSafeNormal(); ControlledPawn->AddMovementInput(WorldDirection, 1.0, false); } } void AUTAD_UIPlayerController::OnSetDestinationReleased() { // If it was a short press if (FollowTime <= ShortPressThreshold) { // We move there and spawn some particles UAIBlueprintHelperLibrary::SimpleMoveToLocation(this, CachedDestination); UNiagaraFunctionLibrary::SpawnSystemAtLocation( this, FXCursor, CachedDestination, FRotator::ZeroRotator, FVector(1.f, 1.f, 1.f), true, true, ENCPoolMethod::None, true); } FollowTime = 0.f; } // Triggered every frame when the input is held down void AUTAD_UIPlayerController::OnTouchTriggered() { bIsTouch = true; OnSetDestinationTriggered(); } void AUTAD_UIPlayerController::OnTouchReleased() { bIsTouch = false; OnSetDestinationReleased(); } void AUTAD_UIPlayerController::OnOpenSkillTree() { ToggleSkillTree(); } void AUTAD_UIPlayerController::ShowMainHUD() { if (MainHUDClass && !MainHUDWidget) { MainHUDWidget = CreateWidget(this, MainHUDClass); if (MainHUDWidget) { MainHUDWidget->AddToViewport(0); } } } void AUTAD_UIPlayerController::ShowSkillTree() { if (!SkillTreeWidget && SkillTreeWidgetClass) { SkillTreeWidget = CreateWidget(this, SkillTreeWidgetClass); } if (SkillTreeWidget && !SkillTreeWidget->IsInViewport()) { SkillTreeWidget->AddToViewport(1); // Set input mode to Game and UI FInputModeGameAndUI InputMode; InputMode.SetWidgetToFocus(SkillTreeWidget->TakeWidget()); InputMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock); SetInputMode(InputMode); bShowMouseCursor = true; } } void AUTAD_UIPlayerController::HideSkillTree() { if (SkillTreeWidget && SkillTreeWidget->IsInViewport()) { SkillTreeWidget->RemoveFromParent(); // Set input mode back to game and UI for top-down gameplay // This allows mouse clicks to work for character movement FInputModeGameAndUI InputMode; InputMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock); InputMode.SetHideCursorDuringCapture(false); SetInputMode(InputMode); // Keep mouse cursor visible for top-down game bShowMouseCursor = true; } } void AUTAD_UIPlayerController::ToggleSkillTree() { if (SkillTreeWidget && SkillTreeWidget->IsInViewport()) { HideSkillTree(); } else { ShowSkillTree(); } }