[언리얼 C++] 캐릭터 동작 구현

chooha·2025년 1월 31일

1. Character 클래스에 액션 바인딩 추가

▸ Character 헤더 파일

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "SpartaCharacter.generated.h"

// EnhancedInput에서 액션 값을 받을 때 사용하는 구조체
struct FInputActionValue;

UCLASS()
class SPARTA_API ASpartaCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	ASpartaCharacter();

protected:

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
	class USpringArmComponent* SpringArmComp;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
	class UCameraComponent* CameraComp;

	// Sprint 액션에 사용되는 변수
	// 기본 스피드
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
	float NormalSpeed;
	// 스피드 변화 값
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
	float SprintSpeedMultiplier;
	// Sprint 상태일 때 스피드
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
	float SprintSpeed;

public:	

	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

	// 입력이 들어왔을 때 실제로 호출되는 함수
	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);
};

▸ Character cpp 파일 - SetupPlayerInputComponent()

#include "SpartaCharacter.h"
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
#include "SpartaPlayerController.h"
#include "EnhancedInputComponent.h"
#include "GameFramework/CharacterMovementComponent.h"

void ASpartaCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	//Enhanced Input Component 로 캐스팅
	if (UEnhancedInputComponent* EnhancedInput = Cast<UEnhancedInputComponent>(PlayerInputComponent))
	{
    	// IA를 가져오기 위해 현재 소유중인 Controller를 ASpartaPlayerController로 캐스팅
		if (ASpartaPlayerController* PlayerController = Cast<ASpartaPlayerController>(GetController()))
		{
        	// IA_Move(WASD) 입력이 들어왔을 때
			if (PlayerController->MoveAction)
			{
            	//키를 누르고 있는동안 Move() 호출
				EnhancedInput->BindAction(
					PlayerController->MoveAction, 
					ETriggerEvent::Triggered, 
					this, 
					&ASpartaCharacter::Move
				);
			}
            // IA_Jump(Spacebar) 입력이 들어왔을 때
			if (PlayerController->JumpAction)
			{
            	// 키를 누르고 있는 동안 StartJump() 호출
				EnhancedInput->BindAction(
					PlayerController->JumpAction,
					ETriggerEvent::Triggered,
					this,
					&ASpartaCharacter::StartJump
				);
				// 키를 뗀 순간 StopJump() 호출
				EnhancedInput->BindAction(
					PlayerController->JumpAction,
					ETriggerEvent::Completed,
					this,
					&ASpartaCharacter::StopJump
				);
			}
            // IA_Look(마우스 이동) 입력이 들어왔을 때
			if (PlayerController->LookAction)
			{
            	// 마우스가 움직일 때 Look() 호출
				EnhancedInput->BindAction(
					PlayerController->LookAction,
					ETriggerEvent::Triggered,
					this,
					&ASpartaCharacter::Look
				);
			}
            // IA_Sprint(Left Shift) 입력이 들어왔을 때
			if (PlayerController->SprintAction)
			{
            	// 키를 누르고 있는 동안 StartSprint() 호출
				EnhancedInput->BindAction(
					PlayerController->SprintAction,
					ETriggerEvent::Triggered,
					this,
					&ASpartaCharacter::StartSprint
				);
				// 키를 뗀 순간 StopSprint() 호출
				EnhancedInput->BindAction(
					PlayerController->SprintAction,
					ETriggerEvent::Completed,
					this,
					&ASpartaCharacter::StopSprint
				);
			}
		}
	}
}
  • BindAction()
    - 첫번째 인자 : UInputAction
    - 두번째 인자 : 액션이 발생하는 트리거 이벤트
    - 세번째 인자 : 액션 발생 시 실행할 객체
    - 네번째 인자 : 액션 발생 시 실행할 함수 포인터

2. Move 구현

void ASpartaCharacter::Move(const FInputActionValue& value)
{
	// 컨트롤러가 있어야 방향 계산이 가능
	if (!Controller) return;

	// IA_Move는 Axis2D로 입력값을 받기 때문에 value는 (X, Y) 형태
    // W → (X, 0), S → (-X, 0), A → (0, Y), D → (0, -Y)
	const FVector2D MoveInput = value.Get<FVector2D>();

	// X값이 있을 때
	if (!FMath::IsNearlyZero(MoveInput.X))
	{
    	// 정면으로 X축 이동
		AddMovementInput(GetActorForwardVector(), MoveInput.X);
	}
	
    // Y값이 있을 때
	if (!FMath::IsNearlyZero(MoveInput.Y))
	{
    	// 우측 방향으로 Y축 이동
		AddMovementInput(GetActorRightVector(), MoveInput.Y);
	}
}
  • AddMovementInput()
    - 어느 방향을 얼만큼 이동할 지 전달하는 함수
    - 첫번째 인자 : 월드좌표 기준 방향
    - 두번째 인자 : 이동 스케일(속도)

  • GetActorForwardVector(), GetActorRightVector()
    월드 좌표에서 액터의 X(forward), Y(Right) 방향 벡터를 가져옴 (length 1.0)

  • FMath::IsNearlyZero()
    - 부동 소수점을 쓸때는 '값 == 0'을 표현할 때 이 함수를 쓰는 것이 좋음
    - 조금의 오차로 다른 결과가 나오는 것을 방지하기 위해?


3. Jump 구현

void ASpartaCharacter::StartJump(const FInputActionValue& value)
{
	// 키가 눌렸을 때
	if (value.Get<bool>()) Jump();
}

void ASpartaCharacter::StopJump(const FInputActionValue& value)
{
	// 키가 눌리지 않았을 때
	if (!value.Get<bool>()) StopJumping();
}
  • Jump(), StopJumping()
    - Character 클래스에서 기본 제공되는 함수
    - 캐릭터가 점프를 하거나 점프를 멈추도록 만들어 줌

4. Look 구현

void ASpartaCharacter::Look(const FInputActionValue& value)
{
	// 마우스의 움직임을 Axis2D로 받음
	FVector2D LookInput = value.Get<FVector2D>();
	
    // X는 좌우 회전(Yaw)
	AddControllerYawInput(LookInput.X);
	// Y는 상하 회전 (Pitch)
    AddControllerPitchInput(LookInput.Y);
}
  • AddControllerYawInput(), AddControllerPitchInput()
    카메라의 Yaw, Pitch축의 회전값을 변경

  • 마우스 감도 변경
    - 프로젝트 설정에서 변경하기

    - IA_Look에서 변경하기


5. Sprint 구현

ASpartaCharacter::ASpartaCharacter()
{
 	PrimaryActorTick.bCanEverTick = true;

	// 중략

	// 기본 이동 속도
	NormalSpeed = 600.0f;
    // 빠른 이동 시 곱해질 속도 값
	SprintSpeedMultiplier = 1.5f;
    // 빠른 이동 시 이동 속도
	SprintSpeed = NormalSpeed * SprintSpeedMultiplier;

	GetCharacterMovement()->MaxWalkSpeed = NormalSpeed;
}

void ASpartaCharacter::StartSprint(const FInputActionValue& value)
{
	// 키가 눌렸을 때 빠른 이동 속도로
	if (GetCharacterMovement()) GetCharacterMovement()->MaxWalkSpeed = SprintSpeed;
}

void ASpartaCharacter::StopSprint(const FInputActionValue& value)
{
	// 키가 떼졌을 때 기본 이동 속도로
	if (GetCharacterMovement()) GetCharacterMovement()->MaxWalkSpeed = NormalSpeed;
}
  • GetCharacterMovement()
    - ACharacter 클래스에 기본 내장되어 있는 함수
    - UCharacterMovementComponent* 반환

0개의 댓글