연습하면서 출판사 사이트의 소스코드를 죄다 카피해서 복붙했더니 캐릭터가 안움직였다.
안그래도 TopDownProject의 Input이 Enhanced인데 왜 Legacy방식의 Attack Actoion을 만드는지 이상했는데 여기가 문제가 있다. 코드가 다르다. 교재의 소스는 엤날거랑 엤날 인풋액션을 만들어주던지 소스를 뜯어고치던지 해야한다.
그냥 옜날방식 input Action을 ProjectSetting에 추가하기로 했다. 잘된다.
하여간 새로운 TopDownProject의 소스를 보면 Tick()이 없다.
대신 Input Event을 4단계로 구분해 TriggerEvent
EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Started, this, &APangeaPlayerController::OnInputStarted);
EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Triggered, this, &APangeaPlayerController::OnSetDestinationTriggered);
EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Completed, this, &APangeaPlayerController::OnSetDestinationReleased);
EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Canceled, this, &APangeaPlayerController::OnSetDestinationReleased);
Tick()을 사용하지 않고 Left 클릭이 된경우만 AddMovementInput으로 이동시키고 있다.
// Triggered every frame when the input is held down
void APangeaPlayerController::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);
}
}
EnhanceInput | LegacyInput |
// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Templates/SubclassOf.h" #include "GameFramework/PlayerController.h" #include "PangeaPlayerController.generated.h" /** Forward declaration to improve compiling times */ class UNiagaraSystem; class UInputMappingContext; class UInputAction; DECLARE_LOG_CATEGORY_EXTERN(LogTemplateCharacter, Log, All); UCLASS() class APangeaPlayerController : public APlayerController { GENERATED_BODY() public: APangeaPlayerController(); /** Time Threshold to know if it was a short press */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input) float ShortPressThreshold; /** FX Class that we will spawn when clicking */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input) UNiagaraSystem* FXCursor; /** MappingContext */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true")) UInputMappingContext* DefaultMappingContext; /** Jump Input Action */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true")) UInputAction* SetDestinationClickAction; /** Jump Input Action */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true")) UInputAction* SetDestinationTouchAction; protected: /** True if the controlled character should navigate to the mouse cursor. */ uint32 bMoveToMouseCursor : 1; virtual void SetupInputComponent() override; // To add mapping context virtual void BeginPlay(); /** Input handlers for SetDestination action. */ void OnInputStarted(); void OnSetDestinationTriggered(); void OnSetDestinationReleased(); void OnTouchTriggered(); void OnTouchReleased(); private: FVector CachedDestination; bool bIsTouch; // Is it a touch device float FollowTime; // For how long it has been pressed }; |
// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Templates/SubclassOf.h" #include "GameFramework/PlayerController.h" #include "PangaeaPlayerController.generated.h" /** Forward declaration to improve compiling times */ class UNiagaraSystem; UCLASS() class APangaeaPlayerController : public APlayerController { GENERATED_BODY() public: APangaeaPlayerController(); /** Time Threshold to know if it was a short press */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input) float ShortPressThreshold; /** FX Class that we will spawn when clicking */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input) UNiagaraSystem* FXCursor; protected: /** True if the controlled character should navigate to the mouse cursor. */ uint32 bMoveToMouseCursor : 1; // Begin PlayerController interface virtual void PlayerTick(float DeltaTime) override; virtual void SetupInputComponent() override; // End PlayerController interface /** Input handlers for SetDestination action. */ void OnSetDestinationPressed(); void OnSetDestinationReleased(); void OnTouchPressed(const ETouchIndex::Type FingerIndex, const FVector Location); void OnTouchReleased(const ETouchIndex::Type FingerIndex, const FVector Location); /** Input Handlers for Attack action. */ void OnAttackPressed(); private: bool bInputPressed; // Input is bring pressed bool bIsTouch; // Is it a touch device float FollowTime; // For how long it has been pressed }; |
// Copyright Epic Games, Inc. All Rights Reserved. #include "PangeaPlayerController.h" #include "GameFramework/Pawn.h" #include "Blueprint/AIBlueprintHelperLibrary.h" #include "NiagaraSystem.h" #include "NiagaraFunctionLibrary.h" #include "PangeaCharacter.h" #include "Engine/World.h" #include "EnhancedInputComponent.h" #include "InputActionValue.h" #include "EnhancedInputSubsystems.h" #include "Engine/LocalPlayer.h" DEFINE_LOG_CATEGORY(LogTemplateCharacter); APangeaPlayerController::APangeaPlayerController() { bShowMouseCursor = true; DefaultMouseCursor = EMouseCursor::Default; CachedDestination = FVector::ZeroVector; FollowTime = 0.f; } void APangeaPlayerController::BeginPlay() { // Call the base class Super::BeginPlay(); //Add Input Mapping Context if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer())) { Subsystem->AddMappingContext(DefaultMappingContext, 0); } } void APangeaPlayerController::SetupInputComponent() { // set up gameplay key bindings Super::SetupInputComponent(); // Set up action bindings if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(InputComponent)) { // Setup mouse input events EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Started, this, &APangeaPlayerController::OnInputStarted); EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Triggered, this, &APangeaPlayerController::OnSetDestinationTriggered); EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Completed, this, &APangeaPlayerController::OnSetDestinationReleased); EnhancedInputComponent->BindAction(SetDestinationClickAction, ETriggerEvent::Canceled, this, &APangeaPlayerController::OnSetDestinationReleased); // Setup touch input events EnhancedInputComponent->BindAction(SetDestinationTouchAction, ETriggerEvent::Started, this, &APangeaPlayerController::OnInputStarted); EnhancedInputComponent->BindAction(SetDestinationTouchAction, ETriggerEvent::Triggered, this, &APangeaPlayerController::OnTouchTriggered); EnhancedInputComponent->BindAction(SetDestinationTouchAction, ETriggerEvent::Completed, this, &APangeaPlayerController::OnTouchReleased); EnhancedInputComponent->BindAction(SetDestinationTouchAction, ETriggerEvent::Canceled, this, &APangeaPlayerController::OnTouchReleased); } 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 APangeaPlayerController::OnInputStarted() { StopMovement(); } // Triggered every frame when the input is held down void APangeaPlayerController::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 APangeaPlayerController::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 APangeaPlayerController::OnTouchTriggered() { bIsTouch = true; OnSetDestinationTriggered(); } void APangeaPlayerController::OnTouchReleased() { bIsTouch = false; OnSetDestinationReleased(); } |
// Copyright Epic Games, Inc. All Rights Reserved. #include "PangaeaPlayerController.h" #include "GameFramework/Pawn.h" #include "Blueprint/AIBlueprintHelperLibrary.h" #include "NiagaraSystem.h" #include "NiagaraFunctionLibrary.h" #include "PangaeaCharacter.h" #include "Engine/World.h" #include "PlayerAvatar.h" APangaeaPlayerController::APangaeaPlayerController() { bShowMouseCursor = true; DefaultMouseCursor = EMouseCursor::Default; } void APangaeaPlayerController::PlayerTick(float DeltaTime) { Super::PlayerTick(DeltaTime); if(bInputPressed) { FollowTime += DeltaTime; // Look for the touch location FVector HitLocation = FVector::ZeroVector; FHitResult Hit; if(bIsTouch) { GetHitResultUnderFinger(ETouchIndex::Touch1, ECC_Visibility, true, Hit); } else { GetHitResultUnderCursor(ECC_Visibility, true, Hit); } HitLocation = Hit.Location; // Direct the Pawn towards that location APawn* const MyPawn = GetPawn(); if(MyPawn) { FVector WorldDirection = (HitLocation - MyPawn->GetActorLocation()).GetSafeNormal(); MyPawn->AddMovementInput(WorldDirection, 1.f, false); } } else { FollowTime = 0.f; } } void APangaeaPlayerController::SetupInputComponent() { // set up gameplay key bindings Super::SetupInputComponent(); InputComponent->BindAction("SetDestination", IE_Pressed, this, &APangaeaPlayerController::OnSetDestinationPressed); InputComponent->BindAction("SetDestination", IE_Released, this, &APangaeaPlayerController::OnSetDestinationReleased); InputComponent->BindAction("Attack", IE_Pressed, this, &APangaeaPlayerController::OnAttackPressed); // support touch devices InputComponent->BindTouch(EInputEvent::IE_Pressed, this, &APangaeaPlayerController::OnTouchPressed); InputComponent->BindTouch(EInputEvent::IE_Released, this, &APangaeaPlayerController::OnTouchReleased); } void APangaeaPlayerController::OnSetDestinationPressed() { // We flag that the input is being pressed bInputPressed = true; // Just in case the character was moving because of a previous short press we stop it StopMovement(); } void APangaeaPlayerController::OnSetDestinationReleased() { // Player is no longer pressing the input bInputPressed = false; // If it was a short press if(FollowTime <= ShortPressThreshold) { // We look for the location in the world where the player has pressed the input FVector HitLocation = FVector::ZeroVector; FHitResult Hit; GetHitResultUnderCursor(ECC_Visibility, true, Hit); HitLocation = Hit.Location; // We move there and spawn some particles UAIBlueprintHelperLibrary::SimpleMoveToLocation(this, HitLocation); UNiagaraFunctionLibrary::SpawnSystemAtLocation(this, FXCursor, HitLocation, FRotator::ZeroRotator, FVector(1.f, 1.f, 1.f), true, true, ENCPoolMethod::None, true); } } void APangaeaPlayerController::OnTouchPressed(const ETouchIndex::Type FingerIndex, const FVector Location) { bIsTouch = true; OnSetDestinationPressed(); } void APangaeaPlayerController::OnTouchReleased(const ETouchIndex::Type FingerIndex, const FVector Location) { bIsTouch = false; OnSetDestinationReleased(); } void APangaeaPlayerController::OnAttackPressed() { auto playerAvatar = Cast<APlayerAvatar>(GetPawn()); if (playerAvatar->CanAttack()) { playerAvatar->Attack(); } } |
'언리얼러닝 > C++스크립트게임개발' 카테고리의 다른 글
네트워크 멀티플레이어 게임 만들기 - RPC (0) | 2025.06.07 |
---|---|
적 캐릭터 생성하기 Enemy Class (1) | 2025.06.07 |
7장 CanAttack() Attack() 함수 구현하기 (0) | 2025.05.27 |
07 PlayerController 캐릭터 제어하기 SimpleMoveToLocation (1) | 2025.05.24 |
게임 액터 생성하기 (0) | 2025.05.16 |