

// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyPawn.generated.h"
class UCapsuleComponent;
class USkeletalMeshComponent;
class USpringArmComponent;
class UCameraComponent;
UCLASS()
class PAWNCLASS_API AMyPawn : public APawn
{
GENERATED_BODY()
public:
AMyPawn();
protected:
virtual void BeginPlay() override;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
class UCapsuleComponent* CapsuleComp;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
class USkeletalMeshComponent* MeshComp;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
class USpringArmComponent* SpringArmComp;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
class UCameraComponent* CameraComp;
public:
virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
};
헤더파일에 컴포넌트 추가
// Sets default values
AMyPawn::AMyPawn()
{
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = false;
CapsuleComp = CreateDefaultSubobject<UCapsuleComponent>(TEXT("CapsuleComp"));
RootComponent = CapsuleComp;
MeshComp = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("MeshComp"));
MeshComp->SetupAttachment(RootComponent);
SpringArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArmComp"));
SpringArmComp->SetupAttachment(RootComponent);
SpringArmComp->TargetArmLength = 300.0f;
SpringArmComp->bUsePawnControlRotation = true;
CameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComp"));
CameraComp->SetupAttachment(SpringArmComp, USpringArmComponent::SocketName);
}
컴포넌트 계층구조 + 상세 설정



방금 만든 Gamemode와 PawnClass를 Default로 지정



Y축이 앞으로 가는걸 기준으로 하려고 하기 때문에
Swizzle을 통해 X에 들어오는 값을 Y의 값으로 바꿔줌
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "MyPlayerController.generated.h"
class UInputMappingContext;
class UInputAction;
class UInputMappingContext;
class UInputAction;
UCLASS()
class PAWNCLASS_API AMyPlayerController : public APlayerController
{
GENERATED_BODY()
public:
AMyPlayerController();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
UInputMappingContext* InputMappingContext;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
UInputAction* MoveAction;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input")
UInputAction* LookAction;
protected:
virtual void BeginPlay() override;
};
입력처리 함수들을 선언
#include "MyPlayerController.h"
#include "EnhancedInputSubsystems.h"
AMyPlayerController::AMyPlayerController()
:InputMappingContext(nullptr),
MoveAction(nullptr),
LookAction(nullptr)
{
}
void AMyPlayerController::BeginPlay()
{
Super::BeginPlay();
if (ULocalPlayer* LocalPlayer = GetLocalPlayer())
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem =
LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>())
{
if (InputMappingContext)
{
Subsystem->AddMappingContext(InputMappingContext, 0);
}
}
}
}
게임이 시작되면 내 플레이어를 찾고,
그 플레이어의 입력 담당 시스템을 찾고,
내가 준비해둔 키 설정표(IMC)가 있으면
그걸 입력 시스템에 등록해라.
라는 의미의 코드.

만들어진 플레이어 컨트롤러에 각각 할당
void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
if (UEnhancedInputComponent* EnhancedInput = Cast<UEnhancedInputComponent>(PlayerInputComponent))
{
if (AMyPlayerController* PlayerController = Cast<AMyPlayerController>(GetController()))
{
if (PlayerController->MoveAction)
{
EnhancedInput->BindAction(
PlayerController->MoveAction,
ETriggerEvent::Triggered,
this,
&AMyPawn::Move
);
}
if (PlayerController->LookAction)
{
EnhancedInput->BindAction(
PlayerController->LookAction,
ETriggerEvent::Triggered,
this,
&AMyPawn::Look
);
}
}
}
}
입력처리 함수들과 액션들을 바인딩
void AMyPawn::Move(const FInputActionValue& value)
{
if (!Controller) return;
const FVector2D MoveInput = value.Get<FVector2D>();
const float DeltaTime = GetWorld()->GetDeltaSeconds();
FVector DeltaLocation = FVector::ZeroVector;
if (!FMath::IsNearlyZero(MoveInput.Y))
{
DeltaLocation += GetActorForwardVector() * MoveInput.Y * MoveSpeed * DeltaTime;
}
if (!FMath::IsNearlyZero(MoveInput.X))
{
DeltaLocation += GetActorRightVector() * MoveInput.X * MoveSpeed * DeltaTime;
}
AddActorLocalOffset(DeltaLocation, true);
}
Move함수를 AddActorLocalOffset()을 활용해 작성
MoveSpeed를 에티터에서 조절가능
DeltaTime을 사용하여 프레임속도와 관계없이 일정한 속도가 나도록 작성
void AMyPawn::Look(const FInputActionValue& value)
{
const FVector2D LookInput = value.Get<FVector2D>();
const float DeltaTime = GetWorld()->GetDeltaSeconds();
const float YawValue = LookInput.X * TurnSpeed * DeltaTime;
const float PitchValue = -LookInput.Y * LookUpSpeed * DeltaTime;
AddActorLocalRotation(FRotator(PitchValue, YawValue, 0.0f));
}
Look함수를 AddActorLocalRotation()을 활용해 작성
Yaw와 Pitch를 계산하여 그냥 넣어주었다.
시연 링크
'unreal 8기' 카테고리의 다른 글
| 2026-6-9 TIL (0) | 2026.06.09 |
|---|---|
| 2026-6-4 TIL (0) | 2026.06.04 |
| [6번 과제] 회전발판과 움직이는 장애물 (0) | 2026.04.09 |
| Unreal Engine C++ 활용 프로그램 제작 (0) | 2026.03.25 |
| 플랫폼 게임 구상하고 만들어보기 (0) | 2026.02.26 |