본문 바로가기
Unreal Engine5/KDT 2024

[UE5 KDT2024] 5. 입력 키 변경하기 EnhanceInput_KeyChange

by 유잉유잉유잉 2025. 2. 17.
728x90

1. 소스코드 디버깅하기

  1. 에디터 끄기 
  2. 솔루션파일 열기(없으면 프로젝트파일 -> Generate Visual Studio project files)디버깅할 솔루션 설정하기 

 

 

중단점 추가 후

솔루션 선택 - 속성 

공용속성 - 시작프로젝트구성 - 한 개의 시작 프로젝트 - 해당 프로젝트명 선택 - 확인

  1. F5 누르면 자동으로 언리얼 에디터 열림.
  • 언리얼 프로젝트에서 실행하면 해당 중단점에서 브레이크걸림.




▶️ 디버깅 선택창 길이 늘리기 

도구 - 사용자지정 - 명령 - 도구모음 - 표준 - 솔루션구성 선택하고 - 선택사항수정 클릭 - 너비를 300정도로 늘리기

솔루션 플랫폼 - 선택사항 누정 - 너비 120정도로 늘리기 



▶️ 솔루션 구성 Debug Editor

Debug : 엔진과 게임 모두 빌드. 

DebugGame : 게임만 디버깅하기 위한 용도.

DebugGame Editor : 디버깅용. 에디터로 실행 

Development : 최적화 없이 엔진과 게임코드 모두 빌드.  

Shipping : 릴리즈용. 디버깅용 정보 제거. 퍼포먼스 최적화 

Test : Shipping과 동일하지만, 프로파일링 툴, 스탯, 콘솔코멘트 유지 

출처 : https://designerd.tistory.com/entry/UE-%EB%B9%8C%EB%93%9C-%ED%99%98%EA%B2%BD%EC%84%A4%EC%A0%95-Debug

 

참고 : https://dev.epicgames.com/documentation/ko-kr/unreal-engine/compiling-game-projects-in-unreal-engine-using-cplusplus?application_version=5.3



 


2. 블루프린트에서 디버깅

1) 블루프린트에서 원하는 함수를 선택 - f9를 누르면 브레이크포인터가 추가됨. 

2) 실행하고 해당 함수가 호출되면 위처럼 알려줌 




 

 


 

2. [이론] NewObject , Outer와 Inner, 가비지 컬렉터 개념 정리 

 

- NewObject : 언리얼에서 제공하는 UObject 타입을 생성하는 함수

런타임에서 오브젝트를 생성하기 위해 사용. (엔진 초기화 이후)

 

  • Outer : 해당 객체를 소유하고 있는 소유자

 

  • Inner : Outer 에 포함되어 있는 객체

 

 

인자로 넣으면 해당 오브젝트가 소유자가 된다. 

위 코드에선 this를 넣었으니 this가 mDefaultInput의 소유자가 됨.

 

⭐⭐ Outer와 Inner의 개념이 중요한 이유 :

- 언리얼은 자체적으로 가비지 컬렉션을 지원함.

* 가비지 컬렉션의 동작원리 : 

  - 모든 객체들의 관계를 조사한다.

  - 루트로부터 시작하여 하나씩 Outer, Inner 관계가 있는지 확인한다.

  - 만약에 어떤 객체가 루트로부터 연결이 되어있지 않다면 해당 객체는 가비지 컬렉션의 대상이 된다. 

 

이미지출처 : https://hyo-ue4study.tistory.com/272

가비지컬렉터 동작 알고리즘은 Mark & Sweep

  1. 마크 : 모든 객체를 돌며 지워질 수 있다고 판단하여 마크를 함. 
  2. 스윕 : 루트서부터 객체를 돌면서 연결이 되어있다면 지워질수 없다고 판단하여 마크를 지움. 
  3. 스윕단계를 거친 후 마크가 남은 애들만 가비지컬랙터가 지워버림 



 


 

3. [개념] CDO 

- T::StaticClass()는 CDO이다. 

- CDO : Class Default Object 

  •  언리얼에서 참조가 일어날 경우 기본적으로 생성되는 객체 

 

- 안에 내부적으로 객체 생성을 확인하게 되면 

new 하고 있지 않고, malloc 을 통해서 메모리 할당을 하게 됨 

 

▶️ new와 malloc의 차이점

-> 생성자를 호출하지 않는다.

 

- 언리얼은 자체적으로 메모리풀을 잡아준다.

 

- CDO 객체를 통해서 만든 데이터는

가급적 런타임중에는 수정을 하지 않는것을 권한다. 



GEngine->AddOnScreenDebugMessage (); 화면에 로그 남기기 




 

4. 런타임 중 키변경 

 

1) 입력액션 IA_KeyChange 생성 

  1. 블프 / input 폴더에 입력-입력액션을 통해 IA_KeyChange 입력액션 생성.
  2. 트리거 - 눌림 추가  => 눌렸을때 한번만 적용 



2) IA_Context 에 IA_KeyChange 추가 

 

3) IA_Move에 액션설명 추가하기

 

4) DefaultInputSystem에 추가 

header

class UInputAction* mKeyChange;

cpp

static ConstructorHelpers::FObjectFinder<UInputAction>
keyAction( L"/Script/EnhancedInput.InputAction'/Game/Blueprint/Input/IA_KeyChange.IA_KeyChange'" );
if ( keyAction.Succeeded() )
	mKeyChange = keyAction.Object;



5) playerBase에 연결 

header

void KeyChangeAction( const struct FInputActionValue& value );

cpp

SetupPlayerInputComponent() 맨하단

inputCp->BindAction( mDefaultInput->mKeyChange, ETriggerEvent::Triggered, this, &APlayerBase::KeyChangeAction );

 



6) KeyChangeAction() 구현 

UInputMappingContext* context = mDefaultInput->mContext;
if ( !IsValid( context ) )
     return;

// TArray : 언리얼에서 제공하는 배열형 자료구조
// GetMappings() : 매핑된 목록 전부(TArray형태로) 가져옴
const TArray<FEnhancedActionKeyMapping>& mappings = context->GetMappings();
// int32 : 언리얼용 signed int
// Num() : TArray에서 갯수 가져오는 함수
int32 cnt = mappings.Num();

for ( int32 i = 0 ; i < cnt ; ++i )
{
      FEnhancedActionKeyMapping& mappingKey = context->GetMapping( i );
      const UInputAction* mappingAction = mappingKey.Action;
      if ( !IsValid( mappingAction ) )
            continue;

if ( mappingAction->ActionDescription.EqualTo( FText::FromString( L"InputMove" ) ) )
{
      // move up
      if ( mappingKey.Key.GetFName() == EKeys::W )
            mappingKey.Key = FKey( EKeys::Up );
      else if ( mappingKey.Key.GetFName() == EKeys::Up )
            mappingKey.Key = FKey( EKeys::W );

      // move down
      if ( mappingKey.Key.GetFName() == EKeys::S )
          mappingKey.Key = FKey( EKeys::Down );
      else if ( mappingKey.Key.GetFName() == EKeys::Down )
            mappingKey.Key = FKey( EKeys::S );

      // move left
      if ( mappingKey.Key.GetFName() == EKeys::A )
            mappingKey.Key = FKey( EKeys::Left );
      else if ( mappingKey.Key.GetFName() == EKeys::Left )
          mappingKey.Key = FKey( EKeys::A );

      // move right
      if ( mappingKey.Key.GetFName() == EKeys::D )
          mappingKey.Key = FKey( EKeys::Right );
      else if ( mappingKey.Key.GetFName() == EKeys::Right )
          mappingKey.Key = FKey( EKeys::D );
}

APlayerController* controller = Cast<APlayerController>( GetController() );
if ( !IsValid( controller ) )
      return;

UEnhancedInputLocalPlayerSubsystem* subSystem =
      ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>( controller->GetLocalPlayer() );

if ( !IsValid( subSystem ) )
      return;

subSystem->RemoveMappingContext( mDefaultInput->mContext );
subSystem->AddMappingContext( mDefaultInput->mContext, 0 );
 



7) 실행하게되면 w,a,s,d로 캐릭터가 움직여지다가

왼쪽 컨트롤키를 누르게되면 화살표키를 이용해야만 캐릭터가 움직이게 된다. 

 

▶️ ULocalPlayer 

개별 플레이어의 화면, 입력, 상태를 관리하는 클래스

 

▶️ 포인터, 참조형 사용시 

isValid() 사용하여 널체크 하는 습관을 들이기 

 

728x90

댓글