ACharacter_Base 의 부모 클래스가 ACharacter인데 Super로 type 재정의를 한 것이다.
(generate_body 에 정의되어 있다.)
#include "EngineMinimal.h" => 자주 사용할 것 같은 기능들, component 를 묶어놓은 헤더
class UNREAL_3TH_API ACharacter_Base : public ACharacter
{
private:
UPROPERTY(EditAnywhere, Category = "Component")
UCameraComponent* m_Cam;
UPROPERTY(EditAnywhere, Category = "Component")
USpringArmComponent* m_Arm;
UPROPERTY(EditAnywhere, Category = "Input")
TSoftObjectPtr<UInputMappingContext> InputMapping;
UPROPERTY(EditAnywhere, Category = "Input")
TSoftObjectPtr<UInputAction> MoveAction;
UPROPERTY(EditAnywhere, Category = "Input")
TSoftObjectPtr<UInputAction> RotationAction;
}
본인쪽 멤버가 주소를 받아서 바로 접근이 가능하게 한다.
* UPROPERTY 사용시 이점
1. EditAnywhere 가 없으면 언리얼에서 디테일창이 뜨지 않는다.
즉, 있어야 디테일 창이 뜬다!
2. 컴포넌트창이 생긴다
ACharacter_Base::ACharacter_Base()
: m_Cam(nullptr)
, m_Arm(nullptr)
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
// TEXT 안에는 이름 부여
// Camera Component 와 SpringArm Component 를 생성해서 ACharacter_Base 에게 추가
// 둘 다 SceneComponent 이다.
m_Cam = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
m_Arm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
// SceneComponent 사이의 계층관계 구조 설정
// 캡슐컴포넌트 밑에 달리게 된다
m_Arm->SetupAttachment(GetCapsuleComponent());
m_Cam->SetupAttachment(m_Arm);
}
CreateDefaultSubobject => 이 안에서 생성하고 Actor에 넣는 기능까지 들어가 있다.
CDO ( Class Default Object ) => 예제 객체가 하나 만들어진다.
블루프린트 스크립트 노드
시퀀스 ==> 앞 뒤 말고 좌우도 있어서 둠
branch ==> true / false
캐릭터 무브먼트 -> add input vector 호출 ( 더블클릭해보면 c++ 함수로 볼 수 있다 )
get actor forward vector -> 앞의 방향 벡터를 가져와서 break vector 2d 의 x와 곱하고 그 값을 add input vector 의 world vector 에 준다.
( 곱한 이유 : w 키를 누르면 앞으로 가고 s 를 누르면 뒤로 가야하기 때문에, 곱해서 -1 이 나오게 하기 위해 )
블루프린트 스크립트 노드를 c++ 로 구현
Build.cs 에 PublicDependencyModuleNames.AddRange(new string[] { "EnhancedInput" }) 작성
위를 적으면 #include "InputMappingContext.h" 을 사용할 수 있다
그리고 비쥬얼스튜디오를 끄고, uproject 오른쪽 마우스 눌러서 generate visual studio project file 누르면 다시 생성된다.
Character_Bace.h
class UNREAL_3TH_API ACharacter_Base : public ACharacter
{
public:
// 에디터상에 공개
// EditAnywhere 가 없으면 언리얼에서 디테일창이 뜨지 않는다
UPROPERTY(EditAnywhere, BlueprintReadWrithe, Category = "Component")
UCameraComponent* m_Cam;
UPROPERTY(EditAnywhere, BlueprintReadWrithe, Category = "Component")
USpringArmComponent* m_Arm;
private:
UPROPERTY(EditAnywhere, Category = "Input")
TSoftObjectPtr<UInputMappingContext> InputMapping;
UPROPERTY(EditAnywhere, Category = "Input")
TSoftObjectPtr<UInputAction> MoveAction;
UPROPERTY(EditAnywhere, Category = "Input")
TSoftObjectPtr<UInputAction> RotationAction;
}
TSoftObjectPtr ==>
Character_Base.cpp
ACharacter_Base::ACharacter_Base()
: m_Cam(nullptr)
, m_Arm(nullptr)
{
// 생성자 시점에서는 아직 값이 안채워져 있다
InputMapping;
MoveAction;
RotationAction;
}
//#include "EnhancedInputSubsystems.h"
//#include "EnhancedInputComponent.h"
// 객체가 만들어지고 나서 레벨이 시작되는 순간
// InputMapping, MoveAction, RotationAction 가 생성이 이미 셋팅이 된 이후
void ACharacter_Base::BeginPlay()
{
// 부모클래스의 BeginPlay 에서 할 일은 부모가 해야되니까
// 블루프린트의 부모인 character 의 BeginPlay 를 실행하게 한다.
Super::BeginPlay();
// APlayerController -> 폰을 상속받은 캐릭터에게 빙의하는 컨트롤러
// Cast -> 다운 캐스팅 (c++의 다이나믹 케스트랑 비슷)
// GetController -> pawn 에서 제공하는 함수
// 현재 컨트롤러를 가져와서 누가 빙의했는지 알려주는 함수 ( player 인지 AI 인지 모르니까 )
// 현재 컨트롤러를 가져와서 APlayerController 로 다운캐스팅하여
// APlayerController 인지 판단하는데, nullptr 이 나오면 AI 이다.
APlayerController* pController = Cast<APlayerController>(GetController());
if (pController)
{
// 우리가 실행하고 있는 프로젝트를 서버적으로 바라봤을 때의 플레이어
ULocalPlayer* pLocalPlayer = pController->GetLocalPlayer();
if (pLocalPlayer)
{
UEnhancedInputLocalPlayerSubsystem* pSubsystem = pLocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>();
pSubsystem->AddMappingContext(InputMapping.LoadSynchronous(), 0);
}
}
}
2.
Character_Bace.h
class UNREAL_3TH_API ACharacter_Base : public ACharacter
{
private:
void Move(const FInputActionInstance& _Instance);
void Rotation(const FInputActionInstance& _Instance);
}
// 컨트롤러가 빙의되는 순간에 입력관련된 처리를 어떻게 할 것인지 actor 에게 호출해주는 함수
// 플레이어 == 컨트롤러
void ACharacter_Base::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
// 입력 액션
// 다운캐스팅해서 실제 클래스타입으로 바꾼다
UEnhancedInputComponent* InputCom = Cast<UEnhancedInputComponent>(PlayerInputComponent);
if (nullptr == InputCom)
return;
InputCom->BindAction(MoveAction.LoadSynchronous(), ETriggerEvent::Triggered, this, &ACharacter_Base::Move);
InputCom->BindAction(RotationAction.LoadSynchronous(), ETriggerEvent::Triggered, this, &ACharacter_Base::Rotation);
}
void ACharacter_Base::Move(const FInputActionInstance& _Instance)
{
// Log-> 하얀색
// Warning -> 노란색
// Error -> 빨간색
// 잘 호출되고 있는지 로그를 찍어본다
//UE_LOG(LogTemp, Warning, TEXT("Call Move Function!!!"));
// FInputActionInstance 를 통해서
FVector2D vInput = _Instance.GetValue().Get<FVector2D>();
// 전방방향 벡터 구해와서 곱한다
if(vInput.X != 0.f)
GetCharacterMovement()->AddInputVector(GetActorForwardVector() * vInput.X);
// 우측방향 벡터 구해와서 곱한다
if (vInput.Y != 0.f)
GetCharacterMovement()->AddInputVector(GetActorRightVector() * vInput.Y);
}
void ACharacter_Base::Rotation(const FInputActionInstance& _Instance)
{
FVector2D vInput = _Instance.GetValue().Get<FVector2D>();
// roll = x 축 회전
// Pitch = 본인의 우측 방향 y 축 회전
// Yaw = z축을 이용해서
// 마우스의 가로 움직임
AddControllerYawInput(vInput.X);
// 마우스의 세로 움직임
AddControllerPitchInput(vInput.Y);
}
* Roll, Pitch, Yaw
[Unreal] Yaw, Pitch, Roll 이해하기 쉽게 알아보기
언리얼 강의를 보게 되면서 코드를 작성하였는데 보이는 의문의 단어들 회전관련되어서 그냥 지나치면서는 언뜻 본것같긴해도 이렇게 얘네 3개가 총 출동하는건 개발하면서 본적이 없어서 따
wise-eun.tistory.com
'언리얼 5' 카테고리의 다른 글
230904 (0) | 2023.09.04 |
---|---|
230901 (0) | 2023.09.01 |
230831 애니메이션 스테이트 머신 / 지금까지 한거 블루프린트 대신 c++ 로 작업해보기 (0) | 2023.08.31 |
230830 회전 블루프린트 / 애니메이션 (0) | 2023.08.30 |
230828 언리얼 엔진 5.1.1 시작 (0) | 2023.08.28 |