이번 시간엔 1인칭 프로젝트를 만들어 c++코드를 살펴보고자 한다!
Class2_2 이름으로 생성하고,파일 탐색기에서 Class2_2.sln을 실행시켜 준다(모든 파일을 보기 위함)
#include "Class2_2Character.generated.h"
GENERATED_BODY()
이 부분은 초기에도 말했듯이 리플렉션을 사용하기 위해 쓰는 것인데 리플렉션이란 프로그램이 자기 자신을 조사하기 위함이다.
해당 부분을 알고있어야 언리얼 상에서 무언갈 표시할 때 표시할 수 있게 하는 것이다.
UCLASS(config=Game)//클래스
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Mesh, meta = (AllowPrivateAccess = "true"))//변수
이 부분은 언리얼에서 사용한다고 등록한다는 의미
가비지 콜렉터: c++언어에는 포함되지 않고 언리얼에 포함된 기능. 쓸모없는 데이터를 정리하는 기능이다.
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Mesh, meta = (AllowPrivateAccess = "true"))
USkeletalMeshComponent* Mesh1P
이 부분에서 포인터로 선언한 Mesh1P는 어딘가에서 사용되고 있을지, 없을지 모르는 상황(클래스가 동작하는 한 동작을 하겠지만)
UPROPERTY를 사용하여 사용중인지 아닌지 판단할 수 있다.
그래서 언리얼에서 변수들은 반드시 UPROPERTY 시스템에 등록하는 것이 중요하다.
나는 분명 Class2_2로 만들었는데 이름이 왜?.. AClass2_2Character
언리얼에서는 엑터를 상속받는 자손들은 반드시 앞에 A를 붙여야 한다. 반대로 언리얼에서 사용하는 언리얼 컴포넌트는 U를 붙인다.
USkeletalMeshComponent* Mesh1P;
왜 포인터? 데이터 자체는 다른데 두고 나는 참조만 하겠다 -> 데이터를 옮기거나 할 때 간단히 하기 위해
-->참조할 때 포인터 안의 값만 참조하면 돼서 간단
FirstPersonCameraComponent = CreateDefaultSubobject(TEXT("FirstPersonCamera"));
// Create a mesh component that will be used when being viewed from a '1st person' view (when controlling this pawn)
Mesh1P = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("CharacterMesh1P"));
Mesh1P->SetOnlyOwnerSee(true); //사용자에게만 보이는 기능
Mesh1P->SetupAttachment(FirstPersonCameraComponent);
Mesh1P->bCastDynamicShadow = false; //움직일 때마다 그림자 생성?
Mesh1P->CastShadow = false; //정적인 그림자 생성?
//Mesh1P->SetRelativeRotation(FRotator(0.9f, -19.19f, 5.2f));
Mesh1P->SetRelativeLocation(FVector(-30.f, 0.f, -150.f)); //상대적인 위치
다음은 input 받았을 때의 상황
void AClass2_2Character::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) //빙의 되었을 때 동작을 묶어줄 수 있다
{
// Set up action bindings
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent))//PlayerInputComponent가 UEnhancedInputComponent의 자손임이 맞으면 EnhancedInputComponent 이 값에 넣어준다
{
// Jumping
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &ACharacter::Jump);// bindaction은 해당 액션 상황(ETriggerEvent::Started)이 들어오면 이 객체(this)에 &ACharacter::Jump함수를 실행시킨다
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping);//&: 함수의 주소값을 사용해 해당 함수를 실행시켜준다
// Moving
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AClass2_2Character::Move);
// Looking
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AClass2_2Character::Look);
}
else
{
UE_LOG(LogTemplateCharacter, Error, TEXT("'%s' Failed to find an Enhanced Input Component! This template is built to use the Enhanced Input system. If you intend to use the legacy system, then you will need to update this C++ file."), *GetNameSafe(this));
}
}
파라미터 부분에서 다소 햇갈리는 부분
void AClass2_2Character::Move(const FInputActionValue& Value) //FInputActionValue: 입력했을 때 그때의 값을 복사해서 받는 것이 아니라 원본(&) 자체를 받겠다->하지만 const로 인해 불가능
{
// input is a Vector2D
FVector2D MovementVector = Value.Get<FVector2D>();
if (Controller != nullptr) //컨트롤러가 있으면
{
// add movement
AddMovementInput(GetActorForwardVector(), MovementVector.Y); //MovementVector 값을 앞쪽으로
AddMovementInput(GetActorRightVector(), MovementVector.X);//MovementVector값을 오른쪽으로
}
}
아우우우~~~ 이번 시간에도 작성된 캐릭터 소스코드를 공부해보는 시간을 가졌습니다~! c, c++, c#모두 다룰 수 있다고 생각했는데 c++은 학부생때나 지금이나 똑같이 어려운 것 같네요 ㅎㅎ 오늘도 수고했습니다~!