인풋 액션의 연결 개념
1. PlayerController는 Enhanced Input Subsystem을 통해 IMC를 활성화한다.
2. 이 IMC는 키보드/마우스/게임패드 등의 입력을 IA에 매핑한다.
3. PlayerController가 유저의 Input을 받아 IA을 트리거한다.
4. PlayerCharacter는 SetupPlayerInputComponent 함수를 통해 IA에 바잉딩된 함수를 호출한다.
*Character.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "PlayerCharacter.generated.h"
class USpringArmComponent;
class UCameraComponent;
struct FInputActionValue;
UCLASS()
class STRIKEZONE_API APlayerCharacter : public ACharacter
{
GENERATED_BODY()
public:
APlayerCharacter();
virtual void Tick(float DeltaTime) override;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
TObjectPtr<USpringArmComponent> SpringArm;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
TObjectPtr<UCameraComponent> ThirdPersonCamera;
private:
float NormalSpeed;
float SprintSpeedMultilier;
float SprintSpeed;
protected:
virtual void BeginPlay() override;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// FInputActionValue는 구조체이기 때문에 복사 비용이 커, Value를 참조함
// EnhancedInputSystem을 사용하려면 리플렉션 시스템에 등록이 되어있어야 엔진에서 읽을 수 있다.
UFUNCTION()
void Move(const FInputActionValue& Value);
UFUNCTION()
void StartJump(const FInputActionValue& Value);
UFUNCTION()
void StopJump(const FInputActionValue& Value);
UFUNCTION()
void Look(const FInputActionValue& Value);
UFUNCTION()
void StartSprint(const FInputActionValue& Value);
UFUNCTION()
void StopSprint(const FInputActionValue& Value);
};
- 각 Action 메서드의 매개변수 FInputActionValue는 구조체이기 때문에 복사 비용이 크기 때문에 참조하여 사용하였다.
- EnhancedInputSystem을 사용하려면 리플렉션 시스템에 등록이 되어 있어야 엔진에서 정상적으로 읽어들일 수 있다. 그래서 UFUNCTION()매크로를 사용하였고, 블루프린트에서 편집하지는 않을 것이기에 인자는 비워두었다.
*Character.cpp
#include "PlayerCharacter.h"
#include "StrikeZonePlayerController.h"
#include "EnhancedInputComponent.h"
#include "Camera/CameraComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
APlayerCharacter::APlayerCharacter()
{
PrimaryActorTick.bCanEverTick = false;
SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
SpringArm->SetupAttachment(RootComponent);
SpringArm->TargetArmLength = 300.0f;
SpringArm->bUsePawnControlRotation = true;
ThirdPersonCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("TP_Camera"));
ThirdPersonCamera->SetupAttachment(SpringArm, USpringArmComponent::SocketName);
ThirdPersonCamera->bUsePawnControlRotation = false;
NormalSpeed = 600.0f;
SprintSpeedMultilier = 1.7f;
SprintSpeed = NormalSpeed * SprintSpeedMultilier;
GetCharacterMovement()->MaxWalkSpeed = NormalSpeed;
}
void APlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
if (UEnhancedInputComponent* EnhancedInput = Cast<UEnhancedInputComponent>(PlayerInputComponent))
{
if (AStrikeZonePlayerController* PlayerController = Cast<AStrikeZonePlayerController>(GetController()))
{
if (PlayerController->MoveAction)
{
EnhancedInput->BindAction(PlayerController->MoveAction, ETriggerEvent::Triggered, this, &APlayerCharacter::Move);
}
if (PlayerController->JumpAction)
{
EnhancedInput->BindAction(PlayerController->JumpAction, ETriggerEvent::Triggered, this, &APlayerCharacter::StartJump);
EnhancedInput->BindAction(PlayerController->JumpAction, ETriggerEvent::Completed, this, &APlayerCharacter::StopJump);
}
if (PlayerController->LookAction)
{
EnhancedInput->BindAction(PlayerController->LookAction, ETriggerEvent::Triggered, this, &APlayerCharacter::Look);
}
if (PlayerController->SprintAction)
{
EnhancedInput->BindAction(PlayerController->SprintAction, ETriggerEvent::Triggered, this, &APlayerCharacter::StartSprint);
EnhancedInput->BindAction(PlayerController->SprintAction, ETriggerEvent::Completed, this, &APlayerCharacter::StopSprint);
}
}
}
}
- EnhancedInputComponent::BindAction 함수에 여러 인자가 존재한다.
- 첫 번째: InputAction을 전달. PlayerController에 있는 해당 UInputAction변수를 연결한다.
- 두 번째: Action이 발생하는 TriggerEvent 종류
- 세 번째: Action을 실행할 객체
- 네 번째: Action의 세부 실행 메서드
*PlayerChracter에 정의된 Action 세부 실행 메서드
void APlayerCharacter::Move(const FInputActionValue& Value)
{
if (!Controller) return;
const FVector2D MoveInput = Value.Get<FVector2D>();
if (!FMath::IsNearlyZero(MoveInput.X))
{
AddMovementInput(GetActorForwardVector(), MoveInput.X);
}
if (!FMath::IsNearlyZero(MoveInput.Y))
{
AddMovementInput(GetActorRightVector(), MoveInput.Y);
}
}
void APlayerCharacter::StartJump(const FInputActionValue& Value)
{
if (Value.Get<bool>())
{
Jump();
}
}
void APlayerCharacter::StopJump(const FInputActionValue& Value)
{
if (!Value.Get<bool>())
{
StopJumping();
}
}
void APlayerCharacter::Look(const FInputActionValue& Value)
{
if (!Controller) return;
const FVector2D LookInput = Value.Get<FVector2D>();
AddControllerPitchInput(LookInput.Y);
AddControllerYawInput(LookInput.X);
}
void APlayerCharacter::StartSprint(const FInputActionValue& Value)
{
if (GetCharacterMovement())
{
GetCharacterMovement()->MaxWalkSpeed = SprintSpeed;
}
}
void APlayerCharacter::StopSprint(const FInputActionValue& Value)
{
if (GetCharacterMovement())
{
GetCharacterMovement()->MaxWalkSpeed = NormalSpeed;
}
}
*PlayerController.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "StrikeZonePlayerController.generated.h"
class UInputMappingContext;
class UInputAction;
UCLASS()
class STRIKEZONE_API AStrikeZonePlayerController : public APlayerController
{
GENERATED_BODY()
public:
AStrikeZonePlayerController();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
TObjectPtr<UInputMappingContext> InputMappingContext;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
TObjectPtr<UInputAction> MoveAction;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
TObjectPtr<UInputAction> JumpAction;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
TObjectPtr<UInputAction> LookAction;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
TObjectPtr<UInputAction> SprintAction;
protected:
virtual void BeginPlay() override;
};
*PlayerController.cpp
#include "StrikeZonePlayerController.h"
#include "EnhancedInputSubsystems.h"
AStrikeZonePlayerController::AStrikeZonePlayerController()
: InputMappingContext(nullptr),
MoveAction(nullptr),
JumpAction(nullptr),
LookAction(nullptr),
SprintAction(nullptr)
{
}
void AStrikeZonePlayerController::BeginPlay()
{
Super::BeginPlay();
if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem =
LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
{
if (InputMappingContext)
{
Subsystem->AddMappingContext(InputMappingContext, 0);
}
}
}
}
- GetLocalPlayer( )는 현재 컨트롤러에서 관리하는 LocalPlayer를 반환한다.
- 이 LocalPlayer에 부착된 Enhanced Input Subsystem을 가져와, AddMappingContext 메서드로 에디터에서 PlayerController에 연결했던 IMC를 활성화 해주었다.
- 두 번째 인자는 우선 순위(Priority)를 의미하며, 특정 IMC가 다른 IMC보다 우선순위가 높도록 설정할 수 있다.
'내배캠 > Unreal Engine' 카테고리의 다른 글
Animation Blueprint로 캐릭터 애니메이션 구현 (0) | 2025.01.23 |
---|---|
FMath::Sin 함수 사용해서 부유하는 느낌의 플랫폼 만들기 (0) | 2025.01.22 |
StaticClass( ) 메서드 (0) | 2025.01.22 |
부동 소수점 연산 오차 (0) | 2025.01.21 |
FRotator와 FQuat (0) | 2025.01.21 |